1. Libraries and functions

1.1 Libraries

Load the required libraries.

library(tidyverse)
library(sf)
library(here)
library(readxl)
library(scales)
library(DT)
library(brms)
library(tidybayes)
library(patchwork)
library(marginaleffects)
library(ggrepel)
library(scico)
library(ggdensity)
library(ggpubr)
library(units)
library(glue)
library(ggh4x)

1.2 Helper functions

Functions that we will use throughout the script

#labeller for years
year_labels <- c(1950:1963)

#The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
#Segment for graphs to match ACF period
acf_start <- decimal_date(ymd("1957-03-11"))
acf_end <- decimal_date(ymd("1957-04-12"))

Function for counterfactual plots



plot_counterfactual <- function(model_data, model, population_denominator, outcome, grouping_var=NULL, re_formula,...){
  
  #labeller for years
  year_labels <- c(1950:1964) #extra year for the extant of the x-axis

  #The Glasgow mass minuture chest X-ray campaign happened between 11th March and 12th April 1957
  #Segment for graphs to match ACF period
  acf_start <- decimal_date(ymd("1957-03-11"))
  acf_end <- decimal_date(ymd("1957-04-12"))

  summary <- {{model_data}} %>%
    select(year, year2, y_num, acf_period, {{population_denominator}}, {{outcome}}, {{grouping_var}}) %>%
    add_epred_draws({{model}}, re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
          .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
          .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                  acf_period=="c. post-acf" ~ "Post Intervention"))



  #create the counterfactual (no intervention), and summarise
  
  counterfact <-
    add_epred_draws(object = {{model}},
                    newdata = {{model_data}} %>%
                                  select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, {{outcome}}) %>%
                                  mutate(acf_period = "a. pre-acf"), re_formula={{re_formula}}) %>%
    group_by(year2, acf_period, {{grouping_var}}) %>%
    mean_qi() %>%
    mutate(.epred_inc = .epred/{{population_denominator}}*100000,
         .epred_inc.lower = .epred.lower/{{population_denominator}}*100000,
         .epred_inc.upper = .epred.upper/{{population_denominator}}*100000) %>%
    mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Before Intervention",
                                acf_period=="c. post-acf" ~ "Post Intervention"))
  


  #plot the intervention effect
p <- summary %>%
    droplevels() %>%
    ggplot() +
    geom_vline(aes(xintercept=acf_start, linetype="Mass CXR screening intervention")) +
    geom_vline(aes(xintercept=acf_end, linetype="Mass CXR screening intervention")) +
    geom_ribbon(aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, group = acf_period, fill=acf_period), alpha=0.5) +
    geom_ribbon(data = counterfact %>% filter(year>=1956), 
                aes(ymin=.epred_inc.lower, ymax=.epred_inc.upper, x=year2, fill="Counterfactual"), alpha=0.5) +
    geom_line(data = counterfact %>% filter(year>=1956), 
              aes(y=.epred_inc, x=year2, colour="Counterfactual")) +
    geom_line(aes(y=.epred_inc, x=year2, group=acf_period,  colour=acf_period)) +
    geom_point(data = {{model_data}} %>%
                 mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Pre-ACF",
                                               acf_period=="b. acf" ~ "ACF",
                                               acf_period=="c. post-acf" ~ "Post-ACF")), 
               aes(y={{outcome}}, x=year2, shape=fct_relevel(acf_period,
                                                             "Pre-ACF",
                                                             "ACF",
                                                             "Post-ACF")), size=2) +
    theme_grey() +
    scale_y_continuous(labels=comma, limits =c(0,400)) +
    scale_x_continuous(labels = year_labels,
                       breaks = year_labels) +
    scale_fill_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="Model estimates:", na.translate = F) +
    scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA") , name="Model estimates:", na.translate = F) +
    scale_shape_discrete(name="Empirical data (period):", na.translate = F) +
    scale_linetype_manual(values = 2, name="") +
    labs(
      x = "",
      y = "CNR (per 100,000)"
    ) +
    guides(x = "axis_truncated", y = "axis_truncated") +
    theme(legend.position = "bottom",
          legend.box="vertical", 
          text = element_text(size=10),
          axis.text.x = element_text(size=10, angle = 90, hjust=1, vjust=0.5),
          legend.text = element_text(size=10),
          legend.spacing.y = unit(0.1, 'cm'),
          axis.line = element_line(colour = "black")) 

    facet_vars <- vars(...)

  if (length(facet_vars) != 0) {
    p <- p + facet_wrap(facet_vars)
  }
  p

}

Function for calculating measures of change over time (RR.peak, RR.level, RR.slope)


summarise_change <- function(model_data, model, population_denominator, grouping_var = NULL, re_formula = NULL) {
  
  #functions for calculating RR.peak
  #i.e. relative case notification rate in 1957 vs. counterfactual trend for 1957
  
  grouping_var <- enquo(grouping_var)
  
  if (!is.null({{grouping_var}})) {
    
    #make the prediction matrix, conditional on whether we want random effects included or not.
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  } else {
    
    out <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 8),
                    acf_period = c("a. pre-acf", "b. acf")
    )
  }
  
  peak_draws <- add_epred_draws(newdata = out,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.peak")
  
  peak_summary <- peak_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.peak")
  
  
  #functions for calculating RR.level
  #i.e. relative case notification rate in 1958 vs. counterfactual trend for 1958
  
    if (!is.null({{grouping_var}})) {
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out2 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num == 9),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    level_draws <- add_epred_draws(newdata = out2,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
    arrange(y_num, .draw) %>%
    mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
    group_by(.draw, !!grouping_var) %>%
    summarise(estimate = last(epred_cnr)/first(epred_cnr)) %>%
    ungroup() %>%
    mutate(measure = "RR.level")
  
  level_summary <- level_draws %>%
    group_by(!!grouping_var) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.level")
    
    
  #functions for calculating RR.slope
  #i.e. relative change in case notification rate in 1958-1963 vs. counterfactual trend for 1959-1963
  
    if (!is.null({{grouping_var}})) {
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num, !!grouping_var) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  } else {
    
    out3 <- crossing({{model_data}} %>% 
                      select({{population_denominator}}, y_num) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf")
    )
  }
  
    slope_draws <- add_epred_draws(newdata = out3,
                  object = {{model}},
                  re_formula = {{re_formula}}) %>%
        arrange(y_num) %>%
        ungroup() %>%
        mutate(epred_cnr = .epred/population_without_inst_ship*100000) %>%
        group_by(.draw, y_num, !!grouping_var) %>%
        summarise(slope = last(epred_cnr)/first(epred_cnr)) %>%
        ungroup() %>%
        group_by(.draw, !!grouping_var) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
  
  slope_summary <- slope_draws %>%
     group_by(!!grouping_var) %>%
      mean_qi(estimate) %>%
      mutate(measure = "RR.slope")
    
  #gather all the results into a named list
    lst(peak_draws=peak_draws, peak_summary=peak_summary, 
        level_draws=level_draws, level_summary=level_summary, 
        slope_draws=slope_draws, slope_summary=slope_summary)
  
}

Function for calculating difference from counterfactual


calculate_counterfactual <- function(model_data, model, population_denominator, grouping_var=NULL, re_formula=NA){
  
  #effect vs. counterfactual
  counterfact <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc_counterf = .epred/{{population_denominator}}*100000, .epred_counterf=.epred)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, .draw, .epred_counterf, .epred_inc_counterf, {{grouping_var}})
  
  #Calcuate case notification rate per draw, then summarise.
  post_change <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, year, {{grouping_var}}, acf_period) %>%
      mutate(.epred_inc = .epred/{{population_denominator}}*100000)  %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, {{population_denominator}}, {{grouping_var}}, .draw, .epred, .epred_inc, {{grouping_var}}) 
  
  #for the overall period
    counterfact_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}) %>%
                                    mutate(acf_period = "a. pre-acf"),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, .draw, .epred, {{grouping_var}})  %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred_counterf = sum(.epred)) 
  
  #Calcuate case notification rate per draw, then summarise.
  post_change_overall <-
      add_epred_draws(object = {{model}},
                      newdata = {{model_data}} %>%
                                    select(year, year2, y_num, {{population_denominator}}, {{grouping_var}}, acf_period),
                      re_formula = {{re_formula}}) %>%
      group_by(.draw, {{grouping_var}}) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select({{population_denominator}}, {{grouping_var}}, .draw, .epred) %>%
      group_by(.draw, {{grouping_var}}) %>%
      summarise(.epred = sum(.epred)) 
  
  
counter_post <-
  left_join(counterfact, post_change) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf,
           diff_inc100k = .epred_inc - .epred_inc_counterf,
           rr_inc100k = .epred_inc/.epred_inc_counterf) %>%
    group_by(year, {{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change, diff_inc100k, rr_inc100k) %>%
    ungroup()

counter_post_overall <-
  left_join(counterfact_overall, post_change_overall) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by({{grouping_var}}) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup()

lst(counter_post, counter_post_overall)

}

Function for tidying up counterfactuals (mostly for making nice tables)


tidy_counterfactuals <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"),
            diff_inc = glue::glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr_inc = glue::glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"))
}


tidy_counterfactuals_overall <- function(data){
  data %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(year = as.character(year),
            cases_averted = glue::glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change} ({pct_change.lower} to {pct_change.upper})"))
}

2. Data

Import datasets for analysis

2.1 Shapefiles

Make a map of Glasgow wards


glasgow_wards_1951 <- st_read(here("mapping/glasgow_wards_1951.geojson"))
Reading layer `glasgow_wards_1951' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/glasgow_wards_1951.geojson' 
  using driver `GeoJSON'
Simple feature collection with 37 features and 3 fields
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: -4.393502 ymin: 55.77464 xmax: -4.070411 ymax: 55.92814
Geodetic CRS:  WGS 84

#read in Scotland boundary
scotland <- st_read(here("mapping/Scotland_boundary/Scotland boundary.shp"))
Reading layer `Scotland boundary' from data source 
  `/Users/petermacpherson/Dropbox/Projects/Historical TB ACF 2023-11-28/Work/analysis/glasgow-cxr/mapping/Scotland_boundary/Scotland boundary.shp' 
  using driver `ESRI Shapefile'
Simple feature collection with 1 feature and 1 field
Geometry type: MULTIPOLYGON
Dimension:     XY
Bounding box:  xmin: 5513 ymin: 530249 xmax: 470332 ymax: 1220302
Projected CRS: OSGB36 / British National Grid
#make a bounding box for Glasgow
bbox <- st_bbox(glasgow_wards_1951) |> st_as_sfc()

#plot scotland with a bounding box around the City of Glasgow
scotland_with_bbox <- ggplot() +
  geom_sf(data = scotland, fill="antiquewhite") +
  geom_sf(data = bbox, colour = "#C60C30", fill="antiquewhite") +
  theme_void() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "#EAF7FA", size = 0.3))

#plot the wards
#note we tidy up some names to fit on map
glasgow_ward_map <- glasgow_wards_1951 %>%
  mutate(ward = case_when(ward=="Shettleston and Tollcross" ~ "Shettleston and\nTollcross",
                          ward=="Partick (West)" ~ "Partick\n(West)",
                          ward=="Partick (East)" ~ "Partick\n(East)",
                          ward=="North Kelvin" ~ "North\nKelvin",
                          ward=="Kinning Park" ~ "Kinning\nPark",
                          TRUE ~ ward)) %>%
  
  ggplot() +
  geom_sf(aes(fill=division)) +
  geom_sf_label(aes(label = ward), size=3, fill=NA, label.size = NA, colour="black") +
  #scale_colour_identity() +
  scale_fill_brewer(palette = "Set3", name="City of Glasgow Division") +
  theme_grey() +
  labs(x="",
       y="",
       fill="Division") +
  theme(legend.position = "top",
        
        panel.border = element_rect(colour = "grey78", fill=NA, linewidth = 0.5),
        panel.background = element_rect(fill = "antiquewhite", size = 0.3),
        panel.grid.major = element_line(color = "grey78")) +
  guides(fill=guide_legend(title.position = "top", title.hjust = 0.5, title.theme = element_text(face="bold")))

#add the map of scotland as an inset
glasgow_ward_map + inset_element(scotland_with_bbox, 0.75, 0, 1, 0.4)

ggsave(here("figures/s1.png"), height=10, width = 12)

NA
NA

Calculate areas per geographical unit

sf_use_s2(FALSE) #https://github.com/r-spatial/sf/issues/1762

glasgow_wards_1951 <- glasgow_wards_1951 %>%
  mutate(area = st_area(glasgow_wards_1951))


glasgow_wards_1951$area_km <- units::set_units(glasgow_wards_1951$area, km^2)

Make division shape files, and calculate area (stopped working, need to fix!)


# glasgow_divisions_1951 <- glasgow_wards_1951 %>%
#   group_by(division) %>% 
#   summarize(geometry = st_union(geometry)) %>%
#   nngeo::st_remove_holes() %>%
#   mutate(area = st_area(glasgow_divisions_1951))
# 
# glasgow_divisions_1951$area_km <- units::set_units(glasgow_divisions_1951$area, km^2)

3. Denominators

Load in the datasets for denonomiators, and check for consistency.


overall_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "overall_population")

overall_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
overall_pops <- overall_pops %>%
  mutate(year2 = year+0.5)

Note, we have three population estimates:

  1. Population without institutionalised people or people in shipping
  2. Population in institutions
  3. Population in shipping

(Population in shipping is estimated from the 1951 census, so is the same for most years)

3.1 Overall population

First, plot the total population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2), alpha=0.5, colour = "mediumseagreen", fill="mediumseagreen") +
  geom_point(aes(y=total_population, x=year2), colour = "mediumseagreen") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: total population",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

Now the population excluding institutionalised and shipping population


overall_pops %>%
  ggplot() +
  geom_area(aes(y=population_without_inst_ship, x=year2), alpha=0.5, colour = "purple", fill="purple") +
  geom_point(aes(y=population_without_inst_ship, x=year2), colour = "purple") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(
    title = "Glasgow Corporation: population excluding institutionalised and shipping",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist()

NA
NA

3.2 Population by Ward

There are 5 Divisions containing 37 Wards in the Glasgow Corporation, with consistent boundaries over time.

#look-up table for divisions and wards
ward_lookup <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "divisions_wards")


ward_pops <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "ward_population")

ward_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()

#shift year to midpoint
ward_pops <- ward_pops %>%
  mutate(year2 = year+0.5)

#Get the Division population
division_pops <- ward_pops %>%
  group_by(division, year) %>%
  summarise(population_without_inst_ship = sum(population_without_inst_ship, na.rm = TRUE),
            institutions = sum(institutions, na.rm = TRUE),
            shipping = sum(shipping, na.rm = TRUE),
            total_population = sum(total_population, na.rm = TRUE))
`summarise()` has grouped output by 'division'. You can override using the `.groups` argument.
division_pops %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Plot the overall population by Division and Ward


division_pops %>%
  mutate(year2 = year+0.5) %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division), alpha=0.8) +
  geom_point(aes(y=total_population, x=year2, colour=division)) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(division~.) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name = "") +
  scale_colour_brewer(palette = "Set3", name = "") +
  labs(
    title = "Glasgow Corporation: total population by Division",
    subtitle = "1950 to 1963",
    x = "Year",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

ward_pops %>%
  ggplot() +
  geom_area(aes(y=total_population, x=year2, colour=division, fill=division)) +
  geom_point(aes(y=total_population, x=year2, colour=division), colour="black") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  facet_wrap(ward~., ncol=6) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  scale_fill_brewer(palette = "Set3", name="Division") +
  scale_colour_brewer(palette = "Set3", name = "Division") +
  labs(
    x = "",
    y = "Population",
    caption = "Mid-year estimates\nMass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

ggsave(here("figures/s2.png"), height=14, width=12)

Approximately, how many person-years of follow-up do we have?


overall_pops %>%
  ungroup() %>%
  summarise(across(year, length, .names = "years"),
            across(c(population_without_inst_ship, total_population), sum)) %>%
  mutate(across(where(is.double), comma)) %>%
  datatable()
NA
NA

Change in population by ward


ward_pops %>%
  group_by(ward) %>%
  summarise(pct_change_pop = (last(population_without_inst_ship) - first(population_without_inst_ship))/first(population_without_inst_ship)) %>%
  mutate(pct_change_pop = percent(pct_change_pop)) %>%
  arrange(pct_change_pop) %>%
  datatable()
NA
NA
NA

Output population density by ward and divison for regression modelling

Wards first

(stopped working, need to fix)


# ward_covariates <-  glasgow_wards_1951 %>%
#   left_join(ward_pops) %>%
#   mutate(people_per_km_sq = as.double(population_without_inst_ship/area_km))
# 
# #plot it out
# 
# ward_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="A") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/ward_pop_density.png"), width=10)
# 
# write_rds(ward_covariates, here("populations/ward_covariates.rds"))

Now divisions first

(stopped working, need to fix)


# division_covariates <-  glasgow_divisions_1951 %>%
#   left_join(division_pops) %>%
#   mutate(people_per_km_sq = as.double(total_population/area_km))
# 
# #plot it out
# 
# division_covariates %>%
#   ggplot() +
#   geom_sf(aes(fill=people_per_km_sq)) + 
#   geom_sf_label(aes(label = division), size=3, fill=NA, label.size = NA, colour="black", family = "Segoe UI") +
#   facet_wrap(year~., ncol=7) +
#   scale_fill_viridis_c(option="G") +
#   theme(legend.position = "bottom",
#         axis.text.x = element_text(angle = 45, hjust=1))
# 
# ggsave(here("figures/division_pop_density.png"), width=10)
# 
# write_rds(division_covariates, here("populations/division_covariates.rds"))

3.3 Population by age and sex


age_sex <- read_xlsx(path = "2023-11-28_glasgow-acf.xlsx", sheet = "age_sex_population") %>%
  pivot_longer(cols = c(male, female),
               names_to = "sex")

#collapse down to smaller age groups to be manageable
age_sex <- age_sex %>%
  ungroup() %>%
  mutate(age = case_when(age == "0 to 4" ~ "00 to 04",
                         age == "5 to 9" ~ "05 to 14",
                         age == "10 to 14" ~ "05 to 14",
                         age == "15 to 19" ~ "15 to 24",
                         age == "20 to 24" ~ "15 to 24",
                         age == "25 to 29" ~ "25 to 34",
                         age == "30 to 34" ~ "25 to 34",
                         age == "35 to 39" ~ "35 to 44",
                         age == "40 to 44" ~ "35 to 44",
                         age == "45 to 49" ~ "45 to 59",
                         age == "50 to 54" ~ "45 to 59",
                         age == "55 to 59" ~ "45 to 59",
                         TRUE ~ "60 & up")) %>%
  group_by(year, age, sex) %>%
  mutate(value = sum(value)) %>%
  ungroup()



m_age_sex <- lm(value ~ splines::ns(year, knots = 3)*age*sex, data = age_sex)

summary(m_age_sex)
Warning: essentially perfect fit: summary may be unreliable

Call:
lm(formula = value ~ splines::ns(year, knots = 3) * age * sex, 
    data = age_sex)

Residuals:
       Min         1Q     Median         3Q        Max 
-1.185e-10  0.000e+00  0.000e+00  0.000e+00  1.185e-10 

Coefficients: (14 not defined because of singularities)
                                                    Estimate Std. Error    t value Pr(>|t|)    
(Intercept)                                        5.222e+04  2.040e-10  2.559e+14   <2e-16 ***
splines::ns(year, knots = 3)1                     -8.043e+03  4.071e-10 -1.976e+13   <2e-16 ***
splines::ns(year, knots = 3)2                             NA         NA         NA       NA    
age05 to 14                                        3.669e+04  2.499e-10  1.468e+14   <2e-16 ***
age15 to 24                                       -3.893e+03  2.499e-10 -1.558e+13   <2e-16 ***
age25 to 34                                       -3.996e+04  2.499e-10 -1.599e+14   <2e-16 ***
age35 to 44                                       -4.230e+04  2.499e-10 -1.693e+14   <2e-16 ***
age45 to 59                                        5.459e+04  2.356e-10  2.317e+14   <2e-16 ***
age60 & up                                         7.533e+04  2.204e-10  3.418e+14   <2e-16 ***
sexmale                                            3.374e+03  2.886e-10  1.169e+13   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14         -1.863e+03  4.985e-10 -3.737e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24          7.533e+04  4.985e-10  1.511e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34          1.325e+05  4.985e-10  2.658e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44          1.380e+05  4.985e-10  2.769e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59          3.474e+03  4.700e-10  7.390e+12   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59                 NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up          -8.453e+04  4.397e-10 -1.923e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up                  NA         NA         NA       NA    
splines::ns(year, knots = 3)1:sexmale             -1.994e+03  5.757e-10 -3.464e+12   <2e-16 ***
splines::ns(year, knots = 3)2:sexmale                     NA         NA         NA       NA    
age05 to 14:sexmale                                1.053e+04  3.534e-10  2.980e+13   <2e-16 ***
age15 to 24:sexmale                                2.352e+04  3.534e-10  6.656e+13   <2e-16 ***
age25 to 34:sexmale                                1.355e+04  3.534e-10  3.833e+13   <2e-16 ***
age35 to 44:sexmale                               -1.727e+03  3.534e-10 -4.888e+12   <2e-16 ***
age45 to 59:sexmale                                2.774e+03  3.332e-10  8.324e+12   <2e-16 ***
age60 & up:sexmale                                -7.761e+04  3.117e-10 -2.490e+14   <2e-16 ***
splines::ns(year, knots = 3)1:age05 to 14:sexmale -2.049e+04  7.051e-10 -2.906e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age05 to 14:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age15 to 24:sexmale -6.780e+04  7.051e-10 -9.616e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age15 to 24:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age25 to 34:sexmale -3.804e+04  7.051e-10 -5.396e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age25 to 34:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age35 to 44:sexmale -1.171e+04  7.051e-10 -1.661e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age35 to 44:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age45 to 59:sexmale -3.473e+04  6.647e-10 -5.224e+13   <2e-16 ***
splines::ns(year, knots = 3)2:age45 to 59:sexmale         NA         NA         NA       NA    
splines::ns(year, knots = 3)1:age60 & up:sexmale   1.056e+05  6.218e-10  1.698e+14   <2e-16 ***
splines::ns(year, knots = 3)2:age60 & up:sexmale          NA         NA         NA       NA    
---
Signif. codes:  0 ‘***’ 0.001 ‘**’ 0.01 ‘*’ 0.05 ‘.’ 0.1 ‘ ’ 1

Residual standard error: 3.074e-11 on 44 degrees of freedom
Multiple R-squared:      1, Adjusted R-squared:      1 
F-statistic: 6.006e+29 on 27 and 44 DF,  p-value: < 2.2e-16
age_levels <- age_sex %>% select(age) %>% distinct() %>% pull() 

age_sex_nd <- 
  crossing(
    age=age_levels,
    sex=c("male", "female"),
    year = 1950:1963
  )

pred_pops <- age_sex_nd %>% modelr::add_predictions(m_age_sex)
Warning: prediction from a rank-deficient fit may be misleading
pred_pops %>%
  ggplot(aes(x=year, y=pred, colour=age)) +
  geom_line() +
  geom_point() +
  facet_grid(sex~.) +
  scale_y_continuous(labels = comma, limits = c(0, 125000))


#How well do they match up with our overall populations?
pred_pops %>%
  group_by(year) %>%
  summarise(sum_pred_pop = sum(pred)) %>%
  right_join(overall_pops) %>%
  select(year, sum_pred_pop, population_without_inst_ship, total_population) %>%
  pivot_longer(cols = c(sum_pred_pop, population_without_inst_ship, total_population)) %>%
  ggplot(aes(x=year, y=value, colour=name)) +
  geom_point() +
  scale_y_continuous(labels = comma, limits = c(800000, 1250000))
Joining with `by = join_by(year)`

pred_pops %>%
  group_by(year, sex) %>%
  summarise(sum = sum(pred)) %>%
  group_by(year) %>%
  mutate(sex_ratio = first(sum)/last(sum))
`summarise()` has grouped output by 'year'. You can override using the `.groups` argument.

Population pyramids


label_abs <- function(x) {
  comma(abs(x))
}


pred_pops %>%
  ungroup() %>%
  group_by(year) %>%
  mutate(year_pop = sum(pred),
         age_sex_pct = percent(pred/year_pop, accuracy=0.1)) %>%
  mutate(sex = case_when(sex=="male" ~ "Male",
                         sex=="female" ~ "Female")) %>%
  ggplot(
    aes(x = age, fill = sex, 
        y = ifelse(test = sex == "Female",yes = -pred, no = pred))) + 
  geom_bar(stat = "identity") +
  geom_text(aes(label = age_sex_pct),
            position= position_stack(vjust=0.5), colour="black", size=2.5) +
  facet_wrap(year~., ncol=7) +
  coord_flip() +
  scale_y_continuous(labels = label_abs) +
  scale_fill_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  theme_ggdist() +
  theme(axis.text.x = element_text(angle=90, hjust = 1, vjust=0.5),
        legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="") 


ggsave(here("figures/s3.png"), width=10)
Saving 10 x 4.5 in image

Not perfect, but resonably good. But ahhhhh… the age groups don’t align with the case notification age groups! Come back to think about this later.

4. Tuberculosis cases

Import the tuberculosis cases dataset

4.1 Overall notifications

Overall, by year.


cases_by_year <- read_xlsx("2023-11-28_glasgow-acf.xlsx", sheet = "by_year")

cases_by_year%>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


#shift year to midpoint
cases_by_year <- cases_by_year %>%
  mutate(year2 = year+0.5)

Plot the overall number of case notified per year, by pulmonary and extra pulmonary classification.


cases_by_year %>%
  select(-total_notifications, -year) %>%
  pivot_longer(cols = c(pulmonary_notifications, `non-pulmonary_notifications`)) %>%
  mutate(name = case_when(name == "pulmonary_notifications" ~ "Pulmonary TB",
                          name == "non-pulmonary_notifications" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA

4.2 Notifications by Division

Read in the datasets and merge together.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
ward_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_ward", value)) %>%
  pull(value)


cases_by_ward_sex_year <- map_df(ward_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_ward_sex_year %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA

Aggregate together to get cases by division


cases_by_division <- cases_by_ward_sex_year %>%
  left_join(ward_lookup) %>%
  group_by(division, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE))
Joining with `by = join_by(ward)``summarise()` has grouped output by 'division', 'year'. You can override using the `.groups` argument.
#shift year to midpoint
cases_by_division <- cases_by_division %>%
  mutate(year2 = year+0.5) %>%
  ungroup()

cases_by_division  %>%
  select(-year2) %>%
  select(year, everything()) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()


cases_by_division %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

4.3 Notifications by ward



cases_by_ward <- cases_by_ward_sex_year %>%
  group_by(ward, year, tb_type) %>%
  summarise(cases = sum(cases, na.rm = TRUE)) %>%
  ungroup()
`summarise()` has grouped output by 'ward', 'year'. You can override using the `.groups` argument.
cases_by_ward %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  select(year, everything()) %>%
  datatable()

#shift year to midpoint
cases_by_ward <- cases_by_ward %>%
  mutate(year2 = year+0.5)

cases_by_ward %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=cases, x=year2, group = tb_type, fill=tb_type), alpha=0.8) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~., scales = "free_y") +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis notifications by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Number of cases",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA

4.4 Notifications by age and sex

As we don’t have denominators, we will just model the change in counts.


#list all the sheets
all_sheets <- excel_sheets("2023-11-28_glasgow-acf.xlsx")

#get the ward sheets
age_sex_sheets <- enframe(all_sheets) %>%
  filter(grepl("by_age_sex", value)) %>%
  pull(value)


cases_by_age_sex <- map_df(age_sex_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

cases_by_age_sex %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA

4.5 Uptake of screening

What percentage of adults (15+ participated in the intervention in 1957)?

# 
# pred_pops %>%
#   ungroup() %>%
#   filter(year==1957) %>%
#   filter(age != "00 to 04",
#          age != "05 to 14") %>%
#   summarise(total_pop = sum(pred)) %>%
#   mutate(cxr_screened = 622349) %>%
#   mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))
# 
# pred_pops %>%
#   ungroup() %>%
#   filter(year==1957) %>%
#   filter(age != "00 to 04",
#          age != "05 to 14") %>%
#   summarise(total_pop = sum(pred), .by=sex) %>%
#   mutate(cxr_screened = c(340474, 281875)) %>%
#   mutate(pct_pop_cxr_screened = percent(cxr_screened/total_pop))

Note that in the Report of Sir Kenneth Cowan, we have the following estimates of participation (we will use these for the manuscript, as they are not based on my estimates)

male_adult_resident_participation <- 281875
female_adult_resident_participation <- 340474
male_adult_resident_population <- 381713
female_adult_resident_population <- 437588

#overall participation
(male_adult_resident_participation+female_adult_resident_participation)/(male_adult_resident_population+female_adult_resident_population)
[1] 0.7596097
#male participation
male_adult_resident_participation/male_adult_resident_population
[1] 0.7384475
#female participation
female_adult_resident_participation/female_adult_resident_population
[1] 0.7780698

Look at uptake of screening by age and sex



uptake_age_sex <- read_xlsx("2024-03-26_mass_xray_uptake.xlsx", sheet = "uptake_age_sex")

uptake_age_sex %>%
  mutate(uptake = examined/resident_population) %>%
  mutate(examined_l = comma(examined),
         resident_population_l = comma(resident_population),
         uptake_l = percent(uptake, accuracy=0.1)) %>%
  mutate(label = glue("{examined_l}/{resident_population_l} ({uptake_l})")) %>%
  filter(age !="00-14") %>%
  mutate(sex = case_when(sex=="m" ~ "Male",
                         sex=="f" ~ "Female")) %>%
  ggplot(aes(x=age, y=uptake, group=sex, fill=sex)) +
  geom_bar(stat = "identity", position = "dodge") +
  geom_text(aes(label=uptake_l), position = position_dodge(width=0.85),vjust=2) +
  scale_y_continuous(labels=percent) +
  scale_fill_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  labs(x="", y="")

ggsave(here("figures/s4.png"))
Saving 7.29 x 4.5 in image

Uptake by division


uptake_division <- read_xlsx("2024-03-26_mass_xray_uptake.xlsx", sheet = "uptake_division")

division_pops %>%
  filter(year==1957) %>%
  select(division, population_without_inst_ship) %>%
  left_join(uptake_division) %>%
  mutate(pct_pop_examined = examined/population_without_inst_ship)
Joining with `by = join_by(division)`

5 TB case notification rates

5.1 Overall TB case notification rates

Now calculate case notification rates per 100,000 population

Merge the notification and population denominator datasets together.

Here we need to include the whole population (with shipping and institutions) as they are included in the notifications.


overall_inc <- overall_pops %>%
  left_join(cases_by_year)
Joining with `by = join_by(year, year2)`
overall_inc <- overall_inc %>%
  mutate(inc_pulm_100k = pulmonary_notifications/total_population*100000,
         inc_ep_100k = `non-pulmonary_notifications`/total_population*100000,
         inc_100k = total_notifications/total_population*100000)

overall_inc %>%
  select(year, inc_100k, inc_pulm_100k, inc_ep_100k) %>%
  mutate_at(.vars = vars(inc_100k, inc_pulm_100k, inc_ep_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

overall_inc %>%
  select(year2, inc_pulm_100k, inc_ep_100k) %>%
  pivot_longer(cols = c(inc_pulm_100k, `inc_ep_100k`)) %>%
  mutate(name = case_when(name == "inc_pulm_100k" ~ "Pulmonary TB",
                          name == "inc_ep_100k" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=value, x=year2, group = name, fill=name), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

Change in case notification rates pre-intervention

#pre-ACF
overall_inc %>%
  filter(year %in% 1950:1956) %>%
  summarise(change = (((last(inc_pulm_100k)-first(inc_pulm_100k))/first(inc_pulm_100k))/7)*100)

#post-ACF
overall_inc %>%
  filter(year %in% 1958:1963) %>%
  summarise(change = (((last(inc_pulm_100k)-first(inc_pulm_100k))/first(inc_pulm_100k))/6)*100)
NA

5.2 TB case notification rates by Division


division_inc <- division_pops %>%
  left_join(cases_by_division)
Joining with `by = join_by(division, year)`
division_inc <- division_inc %>%
  mutate(inc_100k = cases/total_population*100000)

division_inc %>%
  select(year, division, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

division_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(division~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Division",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Case notification rate (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme_ggdist() +
  theme(legend.position = "bottom")

NA
NA
NA

5.2 TB case notification rates by Ward

Here we will filter out the institutions and harbour from the denominators, as we don’t have reliable population denominators for them.


ward_inc <- ward_pops %>%
  left_join(cases_by_ward)
Joining with `by = join_by(ward, year, year2)`
ward_inc <- ward_inc %>%
  mutate(inc_100k = cases/population_without_inst_ship*100000)

ward_inc %>%
  select(year, ward, tb_type, inc_100k) %>%
  mutate_at(.vars = vars(inc_100k),
            .funs = funs(round)) %>%
  datatable()
Warning: `funs()` was deprecated in dplyr 0.8.0.
Please use a list of either functions or lambdas: 

  # Simple named list: 
  list(mean = mean, median = median)

  # Auto named with `tibble::lst()`: 
  tibble::lst(mean, median)

  # Using lambdas
  list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))

ward_inc %>%
  mutate(tb_type = case_when(tb_type == "Pulmonary" ~ "Pulmonary TB",
                          tb_type == "Non-Pulmonary" ~ "Extra-pulmonary TB")) %>%
  ggplot() +
  geom_area(aes(y=inc_100k, x=year2, group = tb_type, fill=tb_type), alpha=0.5) +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels,
                     guide = guide_axis(angle = 90)) +
  facet_wrap(ward~.) +
  scale_fill_brewer(palette = "Set1", name="") +
  labs(
    title = "Glasgow Corporation: Tuberculosis case notification rate, by Ward",
    subtitle = "1950 to 1963, by TB disease classification",
    x = "Year",
    y = "Incidence (per 100,000)",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: extra-pulmonary TB cases by Division/Ward not reported in 1962-1963"
  ) +
  theme(legend.position = "bottom")

NA
NA
NA
NA

On a map


st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k)) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_viridis_c(name="Case notification rate (per 100,000)",
                       option = "A") +
  theme_ggdist() +
  theme(legend.position = "top",
        legend.key.width = unit(2, "cm"),
        panel.border = element_rect(colour = "grey78", fill=NA)) +
  guides(fill=guide_colorbar(title.position = "top"))
Joining with `by = join_by(division, ward, ward_number)`

6. TB Mortality

6.1 Overall Mortality

Import the TB mortality data.

First, overall deaths. Note that in the original reports, we have a pulmonary TB death rate per million for all years, and numbers of pulmonary TB deaths for each year apart from 1950.


#get the overall mortality sheets
deaths_sheets <- enframe(all_sheets) %>%
  filter(grepl("deaths", value)) %>%
  pull(value)


overall_deaths <- map_df(deaths_sheets, ~read_xlsx(path = "2023-11-28_glasgow-acf.xlsx",
                                sheet = .))

overall_deaths %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.))) %>%
  datatable()
NA
NA
NA

Plot the raw numbers of pulmonary deaths


overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_deaths)) +
  geom_line(colour = "#DE0D92") +
  geom_point(colour = "#DE0D92") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  labs(y="Pulmonary TB deaths per year",
       x = "Year",
       title = "Numbers of pulmonary TB deaths",
       subtitle = "Glasgow, 1950-1963",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)\nNote: no data for 1950") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

NA
NA

Now the incidence of pulmonary TB death

overall_deaths %>%
  ggplot(aes(x=year, y=pulmonary_death_rate_per_100k)) +
  geom_line(colour = "#4D6CFA") +
  geom_point(colour = "#4D6CFA") +
  geom_vline(aes(xintercept=acf_start), linetype=3) +
  geom_vline(aes(xintercept=acf_end), linetype=3) +
  scale_y_continuous(labels=comma) +
  scale_x_continuous(labels = year_labels,
                     breaks = year_labels) +
  labs(y="Annual incidence of death (per 100,000)",
       x = "Year",
    caption = "Mass miniature X-ray campaign period between dashed lines (11th March-12th April 1957)") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA))

ggsave(here("figures/s8.png"), width=10)
Saving 10 x 4.5 in image

6. Table 1

Make Table 1 here, and save for publication.


overall_pops %>% 
  select(year, total_population) %>%
  left_join(overall_inc %>%
              select(year, 
                     pulmonary_notifications, inc_pulm_100k,
                     `non-pulmonary_notifications`, inc_ep_100k,
                     total_notifications, inc_100k)) %>%
  left_join(overall_deaths %>%
              select(year,
                     pulmonary_deaths, pulmonary_death_rate_per_100k)) %>%
  mutate(percent_pulmonary = percent(pulmonary_notifications/(total_notifications ), accuracy=0.1)) %>%
  mutate(across(where(is.numeric) & !(year),  ~round(., digits=1))) %>%
  mutate(across(where(is.numeric) & !(year),  ~comma(.)))
Joining with `by = join_by(year)`Joining with `by = join_by(year)`

Comparison fo age-sex distribution of cases in 1950-1956 vs. 1957


label_abs2 <- function(x) {
  percent(abs(x))
}



cases_by_age_sex %>% 
  ungroup() %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(acf_period, age, sex) %>%
  summarise(cases = sum(cases)) %>%
  ungroup() %>%
  group_by(acf_period) %>%
  mutate(period_total = sum(cases)) %>%
  mutate(pct = cases/period_total) %>%
  mutate(pct2 = case_when(sex=="F" ~ -pct,
                          TRUE ~ pct)) %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
                 mutate(acf_period = case_when(acf_period=="a. pre-acf" ~ "Pre-ACF",
                                               acf_period=="b. acf" ~ "ACF",
                                               acf_period=="c. post-acf" ~ "Post-ACF")) %>%
  ggplot() +
  geom_vline(aes(xintercept=0), linetype=2) +
  geom_point(aes(x=pct2,y=age, colour=fct_relevel(acf_period,
                                                             "Pre-ACF",
                                                             "ACF",
                                                             "Post-ACF")), stat="identity") +
  scale_x_continuous(labels=label_abs2, limits = c(-0.2, 0.2)) +
  scale_colour_manual(values = c("#DE0D92", "grey50", "#4D6CFA")) +
  theme_grey(base_family = "Aptos") +
  labs(x= "<- Female                Percent of cases              Male ->",
       y="") +
  theme(legend.title = element_blank(),
        legend.position = "bottom")
`summarise()` has grouped output by 'acf_period', 'age'. You can override using the `.groups` argument.
ggsave(here("figures/s5.png"))
Saving 7.29 x 4.5 in image

Prepare the datasets for modelling


mdata <- ward_inc %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup()


mdata_extrapulmonary <- ward_inc %>%
  filter(tb_type=="Non-Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  group_by(ward) %>%
  mutate(y_num = row_number()) %>%
  ungroup() %>% 
  filter(year<=1961) #no data for 1962 and 1963


#scaffold for overall predictions
overall_scaffold <- mdata %>%
    select(year, year2, y_num, acf_period, population_without_inst_ship, ward, cases) %>%
    group_by(year, year2, y_num, acf_period) %>%
    summarise(population_without_inst_ship = sum(population_without_inst_ship),
              cases = sum(cases)) %>%
    ungroup() %>%
    mutate(inc_100k = cases/population_without_inst_ship*100000) %>%
    left_join(mdata_extrapulmonary %>% group_by(year) %>%
                summarise(cases_extrapulmonary = sum(cases))) %>%
    mutate(inc_100k_extrapulmonary = cases_extrapulmonary/population_without_inst_ship*100000)
`summarise()` has grouped output by 'year', 'year2', 'y_num'. You can override using the `.groups` argument.Joining with `by = join_by(year)`

7. Pulmonary TB model

7.1 Fit the model and priors

This models the case notification rate over time, with a step change for the intervention, and slope change after the intervention.

Work on the priors a bit. We will build up from less complex to more complex.

  1. intercept only, to predict count of cases

at the intercept, we expect somewhere around 2500. We will set the standard deviation to both 0.5 and 1 to check what it looks like

# 
# c(prior(lognormal(7.600902, 0.5)), #log(2500) = 7.600902
#   prior(lognormal(7.600902, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(2000), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,15000))
# 
# 
# prior(gamma(1, 0.01)) %>%
#   parse_dist() %>%
#   ggplot(aes(y=prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(0.5, 0.95))
# 
# #now fit to a model, and plot some prior realisations
# 
# m_prior1 <- brm(
#   cases ~ 0 + Intercept,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape)
# )
# 
# add_epred_draws(object=m_prior1,
#                 newdata = tibble(intercept=1)) %>%
#   ggplot(aes(x=intercept, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)

Now try to add in a term for the effect of y_num. We anticpate that the number of cases will decline by about 1-5% per year. However, as we are pretty uncertain about this, we will just encode a weakly regularising prior to restrict the year size to sensible ranges.

# 
# 
# m_prior2 <- brm(
#   cases ~ 0 + Intercept + y_num,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num)
# )
# 
# add_epred_draws(object=m_prior2,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)

Now we want to add in a prior for the effect of the acf_intervention. We anticipate the peak to be anywhere between no effect, and a tripling

# 
# m_prior3 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2000), 0.5), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b, coef = y_num) +
#           prior(normal(0, 0.001), class = b)
# )
# 
# 
# add_epred_draws(object=m_prior3,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(labels = comma)
# 

Now we look and see what it looks like with the interactions

# 
# m_prior4 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period,
#   family = negbinomial(),
#   data = overall_scaffold,
#   sample_prior = "only",
#   prior = prior(normal(log(2500), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b)
# )
# 
# add_epred_draws(object=m_prior4,
#                 newdata = overall_scaffold) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# 

Now try adding in the random intercepts


# c(prior(lognormal(3.912023, 0.5)), #log(50) = 3.912023
#   prior(lognormal(3.912023, 1))) %>% 
#   parse_dist() %>% 
#   
#   ggplot(aes(y = prior, dist = .dist, args = .args)) +
#   stat_halfeye(.width = c(.5, .95)) +
#   scale_y_discrete(NULL, labels = str_c("lognormal(log(50), ", c(0.5, 1), ")"),
#                    expand = expansion(add = 0.1)) +
#   xlab(expression(exp(italic(p)(beta[0])))) +
#   coord_cartesian(xlim = c(0,400))
# 
# 
# m_prior5 <- brm(
#   cases ~ y_num + acf_period + y_num:acf_period + ( 1 | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(1), class=sd)
# )
# 
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior5,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)

And add in the random slopes

# 
# m_prior6 <- brm(
#   cases ~ 1 + y_num + acf_period + y_num:acf_period + (1 + y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.1), class = b) +
#           prior(exponential(1), class=sd) +
#           prior(lkj(2), class=cor)
# )
# 
# 
# 
# m_prior6 <- brm(
#   cases ~ 0 + Intercept + y_num + acf_period + y_num:acf_period + ( y_num*acf_period | ward),
#   family = negbinomial(),
#   data = mdata,
#   sample_prior = "only",
#   prior = prior(normal(log(50), 1), class = b, coef = Intercept) +
#           prior(gamma(1, 0.01), class = shape) +
#           prior(normal(0, 0.01), class = b) +
#           prior(exponential(100), class=sd) +
#           prior(lkj(2), class=cor)
# )


# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = NA) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma)
# 
# add_epred_draws(object=m_prior6,
#                 newdata = mdata,
#                 re_formula = ~( 1 + y_num + acf_period | ward)) %>%
#   ggplot(aes(x=year, y=.epred)) +
#   stat_halfeye() +
#   scale_y_log10(label=comma) +
#   facet_wrap(ward~.)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_prior6, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num + acf_period | ward))

Issue here is the non-centred parameterisation of the intercept prior… Feel like this is a more interpretable way to set priors… but will revert to centred parameterisation for the meantime.

# m_centered_prior <- brm(
#   cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
#                   data = mdata,
#                   family = negbinomial(),
#                   seed = 1234,
#                   chains = 4, cores = 4,
#                   prior = prior(normal(0,1000), class = Intercept) +
#                           prior(gamma(0.01, 0.01), class = shape) +
#                           prior(normal(0, 1), class = b) +
#                           prior(exponential(1), class=sd) +
#                           prior(lkj(2), class=cor),
#                   sample_prior = "only")
# 
# plot(m_centered_prior)
# 
# plot_counterfactual(model_data = overall_scaffold, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, re_formula = NA)
# 
# plot_counterfactual(model_data = mdata, model=m_centered_prior, outcome = inc_100k, 
#                     population_denominator = population_without_inst_ship, grouping_var = ward, ward,
#                     re_formula = ~( 1 + y_num*acf_period | ward))

Look at the mean and variance of counts (counts of pulmonary notifications are what we are predicting)


#Mean of counts per year
mean(mdata$cases)
[1] 48.32819
#variance of counts per year
var(mdata$cases)
[1] 915.5749

Quite a bit of over-dispersion here, so negative binomial distribution might be a better choice of distributional family than Poisson.

Fit the model with the data


m_pulmonary <- brm(
  cases ~ 0 + Intercept + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0,1), class=b, coef = "Intercept") +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(4), class=cor),
  control = list(adapt_delta = 0.9))
Compiling Stan program...
Start sampling
starting worker pid=5049 on localhost:11567 at 16:50:13.533
starting worker pid=5070 on localhost:11567 at 16:50:13.746
starting worker pid=5084 on localhost:11567 at 16:50:13.932
starting worker pid=5098 on localhost:11567 at 16:50:14.111
Error in serialize(data, node$con, xdr = FALSE) : 
  error writing to connection

Nicer version of trace plots for supplemental material

as_draws_df(m_pulmonary) %>% 
  bayesplot::mcmc_rank_overlay(pars = vars(b_Intercept:shape),
             facet_args = list(ncol = 4)) +
  scale_colour_scico_d(palette = "managua", name = "Chain") +
  theme_ggdist()+
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "top")
Scale for colour is already present.
Adding another scale for colour, which will replace the existing scale.

Nicer version of table of parameters for supplement


summarise_draws(m_pulmonary) %>%
  mutate(across(c(mean:ess_tail), comma, accuracy=0.01)) %>%
  write_csv(here("figures/s1_table.csv"))
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(c(mean:ess_tail), comma, accuracy = 0.01)`.
Caused by warning:
! The `...` argument of `across()` is deprecated as of dplyr 1.1.0.
Supply arguments directly to `.fns` through an anonymous function instead.

  # Previously
  across(a:b, mean, na.rm = TRUE)

  # Now
  across(a:b, \(x) mean(x, na.rm = TRUE))
This warning is displayed once every 8 hours.
Call `lifecycle::last_lifecycle_warnings()` to see where this warning was generated.

7.2 Summarise change in CNRs

Summarise the posterior in graphical form


f1b <- plot_counterfactual(model_data = overall_scaffold, model = m_pulmonary, 
                           population_denominator = population_without_inst_ship, outcome = inc_100k, grouping_var=NULL,
                           re_formula = NA)
  
f1b

Make this into a figure combined with the map of empirical data


f1a <- st_as_sf(left_join(ward_inc, glasgow_wards_1951)) %>%
  filter(tb_type=="Pulmonary") %>%
  ggplot() +
  geom_sf(aes(fill=inc_100k), colour="grey98", lwd=0.01) +
  facet_wrap(year~., ncol = 7) +
  scale_fill_scico(name="CNR (per 100,000)",
                       palette = "acton", direction = -1) +
  theme_grey() +
  theme(legend.position = "top",
        #legend.key.width = unit(1, "cm"),
        legend.title.align = 0.5,
        axis.text.x = element_blank(),
        axis.text.y = element_blank(),
        axis.line = element_blank(),
        axis.ticks = element_blank(),
        panel.background = element_blank(),
        legend.title = element_text(size=10))
Joining with `by = join_by(division, ward, ward_number)`Warning: The `legend.title.align` argument of `theme()` is deprecated as of ggplot2 3.5.0.
Please use theme(legend.title = element_text(hjust)) instead.
(f1a / f1b) + plot_annotation(tag_levels = "A")

ggsave(here("figures/f1.png"), width=7, height=8)

Summary of change in notifications numerically


overall_change <- summarise_change(model_data=overall_scaffold, model=m_pulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change %>%
  keep((names(.) %in% tokeep)) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA

7.3 Compared to counterfactual

Numbers of pulmonary TB cases averted compared to counterfactual per year.


overall_pulmonary_counterf <- calculate_counterfactual(model_data = overall_scaffold, model=m_pulmonary, population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Joining with `by = join_by(.draw)`
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Total pulmonary TB cases averted between 1958 and 1963


overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

7.4 Correlation between RR.peak, RR.level, and RR.slope

What are the correlations between peak, level, and slope?

7.5 Ward level pulmonary TB estimates

Plot the counterfactual at ward level

Summary of change in notifications at ward level

Calculate the counterfactual per ward


ward_pulmonary_counterf <- calculate_counterfactual(model_data = mdata, model=m_pulmonary, 
                                                    population_denominator = population_without_inst_ship,
                                                    grouping_var = ward, re_formula=~(1 + y_num*acf_period | ward))
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.Joining with `by = join_by(year, population_without_inst_ship, .draw, ward)`Joining with `by = join_by(.draw, ward)`
ward_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Overall counterfactual per ward


ward_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

8. Extra-pulmonary TB notifications

Now we will model the extra-pulmonary TB notification rate. Struggling a bit with negative binomial model, so revert to Poisson.

8.1 Fit the model


m_extrapulmonary <- brm(
  cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)),
                  data = mdata_extrapulmonary,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4,
                  prior = prior(normal(0,1000), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b) +
                          prior(exponential(1), class=sd) +
                          prior(lkj(2), class=cor))
Compiling Stan program...
Start sampling
starting worker pid=98124 on localhost:11567 at 11:02:29.576
starting worker pid=98138 on localhost:11567 at 11:02:29.840
starting worker pid=98152 on localhost:11567 at 11:02:30.070
starting worker pid=98167 on localhost:11567 at 11:02:30.303

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 0.000729 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 7.29 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 0.000445 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 4.45 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 0.000525 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 5.25 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 0.000231 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 2.31 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 20.64 seconds (Warm-up)
Chain 1:                8.876 seconds (Sampling)
Chain 1:                29.516 seconds (Total)
Chain 1: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 20.57 seconds (Warm-up)
Chain 2:                8.787 seconds (Sampling)
Chain 2:                29.357 seconds (Total)
Chain 2: 
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 20.32 seconds (Warm-up)
Chain 4:                8.993 seconds (Sampling)
Chain 4:                29.313 seconds (Total)
Chain 4: 
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 21.638 seconds (Warm-up)
Chain 3:                8.729 seconds (Sampling)
Chain 3:                30.367 seconds (Total)
Chain 3: 
Warning: Bulk Effective Samples Size (ESS) is too low, indicating posterior means and medians may be unreliable.
Running the chains for more iterations may help. See
https://mc-stan.org/misc/warnings.html#bulk-ess
summary(m_extrapulmonary)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ 1 + y_num * acf_period + (1 + y_num * acf_period | ward) + offset(log(population_without_inst_ship)) 
   Data: mdata_extrapulmonary (Number of observations: 444) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Multilevel Hyperparameters:
~ward (Number of levels: 37) 
                                                      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
sd(Intercept)                                             0.33      0.06     0.23     0.46 1.00     1365     2322
sd(y_num)                                                 0.02      0.01     0.00     0.04 1.01      384     1066
sd(acf_periodb.acf)                                       0.11      0.09     0.00     0.33 1.00     2084     1637
sd(acf_periodc.postMacf)                                  0.12      0.09     0.01     0.34 1.01     1322     1811
sd(y_num:acf_periodb.acf)                                 0.01      0.01     0.00     0.04 1.00     1909     1615
sd(y_num:acf_periodc.postMacf)                            0.01      0.01     0.00     0.04 1.00      906     1267
cor(Intercept,y_num)                                     -0.12      0.31    -0.66     0.53 1.00     1969     2669
cor(Intercept,acf_periodb.acf)                           -0.01      0.33    -0.64     0.62 1.00     5360     3024
cor(y_num,acf_periodb.acf)                               -0.00      0.33    -0.65     0.62 1.00     4082     2934
cor(Intercept,acf_periodc.postMacf)                      -0.07      0.32    -0.65     0.57 1.00     4841     2964
cor(y_num,acf_periodc.postMacf)                          -0.04      0.33    -0.64     0.59 1.00     3930     3058
cor(acf_periodb.acf,acf_periodc.postMacf)                 0.03      0.33    -0.62     0.66 1.00     2814     2651
cor(Intercept,y_num:acf_periodb.acf)                     -0.01      0.33    -0.63     0.63 1.00     5389     3013
cor(y_num,y_num:acf_periodb.acf)                         -0.02      0.33    -0.62     0.60 1.00     3765     3248
cor(acf_periodb.acf,y_num:acf_periodb.acf)               -0.08      0.35    -0.71     0.59 1.00     3816     3404
cor(acf_periodc.postMacf,y_num:acf_periodb.acf)           0.01      0.33    -0.62     0.63 1.00     3414     3206
cor(Intercept,y_num:acf_periodc.postMacf)                -0.14      0.32    -0.69     0.51 1.00     3844     2636
cor(y_num,y_num:acf_periodc.postMacf)                    -0.05      0.33    -0.65     0.59 1.00     3222     2957
cor(acf_periodb.acf,y_num:acf_periodc.postMacf)           0.02      0.33    -0.59     0.64 1.00     2776     3075
cor(acf_periodc.postMacf,y_num:acf_periodc.postMacf)     -0.08      0.35    -0.72     0.60 1.00     2433     2632
cor(y_num:acf_periodb.acf,y_num:acf_periodc.postMacf)     0.02      0.33    -0.61     0.64 1.00     2168     3141

Regression Coefficients:
                           Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                     -7.93      0.08    -8.08    -7.78 1.00     1561     2465
y_num                         -0.09      0.01    -0.11    -0.06 1.00     4286     2639
acf_periodb.acf               -0.00      0.97    -1.94     1.87 1.00     2620     3110
acf_periodc.postMacf          -0.33      0.40    -1.12     0.47 1.00     2470     2788
y_num:acf_periodb.acf         -0.01      0.12    -0.25     0.23 1.00     2628     3187
y_num:acf_periodc.postMacf     0.02      0.04    -0.06     0.09 1.00     2251     2732

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape    93.62     65.60    27.13   273.55 1.00     4326     3542

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_extrapulmonary)

pp_check(m_extrapulmonary, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

8.2 Summary of change

Summarise in plot

ggsave(here("figures/s9.png"), width=10)
Saving 10 x 7 in image

Summarise numerically.


overall_change_extrapulmonary <- summarise_change(model_data=overall_scaffold, model=m_extrapulmonary, 
                                   population_denominator=population_without_inst_ship, grouping_var=NULL, re_formula = NA)
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
overall_change_extrapulmonary %>%
  keep(names(.) %in% tokeep) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA

8.3 Compared to counterfactual

Numbers of extra-pulmonary TB cases averted overall.


overall_ep_counterf <- calculate_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, 
                                               population_denominator = population_without_inst_ship)
Joining with `by = join_by(year, population_without_inst_ship, .draw)`Joining with `by = join_by(.draw)`
overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA

Total extrapulmonary TB cases averted between 1958 and 1963


overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  datatable()
NA
NA

Make into Table 2

bind_rows(
overall_pulmonary_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "PTB_ward"),

overall_pulmonary_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "PTB_overall"),

overall_ep_counterf$counter_post %>%
  mutate(across(c(cases_averted:cases_averted.upper, diff_inc100k:diff_inc100k.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(rr_inc100k:rr_inc100k.upper), number_format(accuracy = 0.01))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "EPTB"),

overall_ep_counterf$counter_post_overall %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  mutate(model = "EPTB overall")

) %>%
  select(model, year, diff_inc100k, diff_inc100k.lower:rr_inc100k.upper, 
         cases_averted:cases_averted.upper,
         pct_change:pct_change.upper) %>%
  transmute(model=model, year=year,
            diff_cnr = glue("{diff_inc100k} ({diff_inc100k.lower} to {diff_inc100k.upper})"),
            rr = glue("{rr_inc100k} ({rr_inc100k.lower} to {rr_inc100k.upper})"),
            cases_averted = glue("{cases_averted} ({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue("{pct_change} ({pct_change.lower} to {pct_change.upper})")) %>%
  write_csv(here("figures/table2.csv"))

8.4 Ward-level extra-pulmonary summaries

Ward-level extra-pulmonary estimates in graphical form.

plot_counterfactual(model_data = mdata_extrapulmonary, model=m_extrapulmonary, outcome = inc_100k, 
                    population_denominator = population_without_inst_ship, grouping_var = ward,re_formula =~(y_num*acf_period | ward), 
                    ward) + scale_y_continuous(limits= c(0,75))
Scale for y is already present.
Adding another scale for y, which will replace the existing scale.

Numerical summary.


ward_change_extrapulmonary <- summarise_change(model_data = mdata_extrapulmonary, model = m_extrapulmonary, 
                                population_denominator = population_without_inst_ship, grouping_var=ward,
                                re_formula = ~(y_num*acf_period | ward)) 
`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'y_num'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw'. You can override using the `.groups` argument.
#want to keep the summary estimates here
tokeep <- c("peak_summary", "level_summary", "slope_summary")

#summary measures in a table
ward_change_extrapulmonary  %>%
  keep(names(.) %in% tokeep) %>%
  bind_rows() %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA
NA

9. Age-sex model

9.1 FIt the model

Fit the model

(Not rewritten the functions for this yet)


mdata_age_sex <- cases_by_age_sex %>%
  filter(tb_type=="Pulmonary") %>%
  mutate(acf_period = case_when(year %in% c(1950:1956) ~ "a. pre-acf",
                                year %in% c(1957) ~ "b. acf",
                                year %in% c(1958:1963) ~ "c. post-acf")) %>%
  mutate(year2 = year+0.5) %>%
  group_by(age, sex) %>%
  mutate(y_num = row_number()) %>%
  ungroup()

m_age_sex <- brm(
  cases ~ y_num + (acf_period)*(age*sex) + (acf_period:y_num)*(age*sex),
                  data = mdata_age_sex,
                  family = negbinomial(),
                  seed = 1234,
                  chains = 4, cores = 4, 
                  prior = prior(normal(0,1), class = Intercept) +
                          prior(gamma(0.01, 0.01), class = shape) +
                          prior(normal(0, 1), class = b))
Compiling Stan program...
Start sampling
starting worker pid=98428 on localhost:11567 at 11:05:18.993
starting worker pid=98442 on localhost:11567 at 11:05:19.345
starting worker pid=98462 on localhost:11567 at 11:05:20.507
starting worker pid=98476 on localhost:11567 at 11:05:20.732

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 1).
Chain 1: 
Chain 1: Gradient evaluation took 6.2e-05 seconds
Chain 1: 1000 transitions using 10 leapfrog steps per transition would take 0.62 seconds.
Chain 1: Adjust your expectations accordingly!
Chain 1: 
Chain 1: 
Chain 1: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 2).
Chain 2: 
Chain 2: Gradient evaluation took 8.3e-05 seconds
Chain 2: 1000 transitions using 10 leapfrog steps per transition would take 0.83 seconds.
Chain 2: Adjust your expectations accordingly!
Chain 2: 
Chain 2: 
Chain 2: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 3).
Chain 3: 
Chain 3: Gradient evaluation took 5.6e-05 seconds
Chain 3: 1000 transitions using 10 leapfrog steps per transition would take 0.56 seconds.
Chain 3: Adjust your expectations accordingly!
Chain 3: 
Chain 3: 
Chain 3: Iteration:    1 / 2000 [  0%]  (Warmup)

SAMPLING FOR MODEL 'anon_model' NOW (CHAIN 4).
Chain 4: 
Chain 4: Gradient evaluation took 5.8e-05 seconds
Chain 4: 1000 transitions using 10 leapfrog steps per transition would take 0.58 seconds.
Chain 4: Adjust your expectations accordingly!
Chain 4: 
Chain 4: 
Chain 4: Iteration:    1 / 2000 [  0%]  (Warmup)
Chain 1: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 3: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 2: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 4: Iteration:  200 / 2000 [ 10%]  (Warmup)
Chain 1: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 4: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 2: Iteration:  400 / 2000 [ 20%]  (Warmup)
Chain 3: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 1: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 4: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 2: Iteration:  600 / 2000 [ 30%]  (Warmup)
Chain 3: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 1: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 4: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 2: Iteration:  800 / 2000 [ 40%]  (Warmup)
Chain 3: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 3: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 4: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 4: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 1: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 1: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 2: Iteration: 1000 / 2000 [ 50%]  (Warmup)
Chain 2: Iteration: 1001 / 2000 [ 50%]  (Sampling)
Chain 3: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 1: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 2: Iteration: 1200 / 2000 [ 60%]  (Sampling)
Chain 4: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 3: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 1: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 2: Iteration: 1400 / 2000 [ 70%]  (Sampling)
Chain 4: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 3: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 2: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 1: Iteration: 1600 / 2000 [ 80%]  (Sampling)
Chain 4: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 3: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 2: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 1: Iteration: 1800 / 2000 [ 90%]  (Sampling)
Chain 4: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 4: 
Chain 4:  Elapsed Time: 16.959 seconds (Warm-up)
Chain 4:                18.942 seconds (Sampling)
Chain 4:                35.901 seconds (Total)
Chain 4: 
Chain 3: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 3: 
Chain 3:  Elapsed Time: 16.574 seconds (Warm-up)
Chain 3:                19.863 seconds (Sampling)
Chain 3:                36.437 seconds (Total)
Chain 3: 
Chain 2: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 2: 
Chain 2:  Elapsed Time: 18.234 seconds (Warm-up)
Chain 2:                19.542 seconds (Sampling)
Chain 2:                37.776 seconds (Total)
Chain 2: 
Chain 1: Iteration: 2000 / 2000 [100%]  (Sampling)
Chain 1: 
Chain 1:  Elapsed Time: 18.018 seconds (Warm-up)
Chain 1:                20.185 seconds (Sampling)
Chain 1:                38.203 seconds (Total)
Chain 1: 
summary(m_age_sex)
 Family: negbinomial 
  Links: mu = log; shape = identity 
Formula: cases ~ y_num + (acf_period) * (age * sex) + (acf_period:y_num) * (age * sex) 
   Data: mdata_age_sex (Number of observations: 224) 
  Draws: 4 chains, each with iter = 2000; warmup = 1000; thin = 1;
         total post-warmup draws = 4000

Regression Coefficients:
                                         Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
Intercept                                    4.42      0.11     4.20     4.64 1.00     1397     2401
y_num                                       -0.17      0.03    -0.23    -0.11 1.00     1352     2186
acf_periodb.acf                             -0.02      0.99    -1.98     1.94 1.00     6206     2892
acf_periodc.postMacf                        -0.50      0.33    -1.15     0.15 1.00     2432     2868
age06_15                                     0.63      0.15     0.34     0.93 1.00     1844     2734
age16_25                                     1.85      0.13     1.60     2.12 1.00     1587     2376
age26_35                                     1.13      0.14     0.86     1.40 1.00     1700     2530
age36_45                                     0.28      0.15    -0.01     0.57 1.00     1880     2731
age46_55                                    -0.62      0.17    -0.97    -0.27 1.00     2170     2602
age56_65                                    -1.08      0.19    -1.46    -0.71 1.00     2551     2927
age65P                                      -1.64      0.22    -2.07    -1.21 1.00     2964     3032
sexM                                         0.16      0.15    -0.13     0.46 1.00     1413     2537
age06_15:sexM                               -0.43      0.21    -0.83    -0.03 1.00     2045     2796
age16_25:sexM                               -0.58      0.18    -0.94    -0.23 1.00     1713     2556
age26_35:sexM                               -0.33      0.19    -0.70     0.04 1.00     1668     2681
age36_45:sexM                                0.24      0.20    -0.16     0.62 1.00     1941     2649
age46_55:sexM                                1.15      0.22     0.72     1.57 1.00     1947     2397
age56_65:sexM                                1.13      0.24     0.67     1.59 1.00     2309     2597
age65P:sexM                                  1.00      0.26     0.47     1.50 1.00     2723     3163
acf_periodb.acf:age06_15                     0.01      1.00    -1.95     1.95 1.00     7072     2973
acf_periodc.postMacf:age06_15               -0.59      0.51    -1.57     0.45 1.00     3737     3352
acf_periodb.acf:age16_25                     0.04      0.98    -1.88     1.90 1.00     6437     2778
acf_periodc.postMacf:age16_25                0.74      0.42    -0.08     1.58 1.00     3367     3236
acf_periodb.acf:age26_35                     0.05      1.01    -1.95     2.01 1.00     6205     2400
acf_periodc.postMacf:age26_35                0.66      0.43    -0.19     1.50 1.00     3365     3163
acf_periodb.acf:age36_45                     0.04      1.03    -2.00     2.07 1.00     6355     2766
acf_periodc.postMacf:age36_45                0.75      0.46    -0.15     1.66 1.00     3567     3174
acf_periodb.acf:age46_55                     0.06      0.98    -1.86     1.95 1.00     7318     2828
acf_periodc.postMacf:age46_55                0.86      0.48    -0.06     1.78 1.00     3668     2624
acf_periodb.acf:age56_65                     0.03      0.99    -1.84     1.96 1.00     7096     2983
acf_periodc.postMacf:age56_65                0.63      0.52    -0.36     1.64 1.00     3886     2904
acf_periodb.acf:age65P                       0.06      0.97    -1.81     1.96 1.00     7553     3091
acf_periodc.postMacf:age65P                  0.97      0.54    -0.11     1.99 1.00     3746     2598
acf_periodb.acf:sexM                        -0.00      1.01    -2.00     1.96 1.00     6464     3241
acf_periodc.postMacf:sexM                   -0.06      0.37    -0.78     0.66 1.00     2954     3273
y_num:acf_periodb.acf                       -0.10      0.13    -0.36     0.16 1.00     5945     2661
y_num:acf_periodc.postMacf                   0.04      0.04    -0.03     0.12 1.00     2137     2900
acf_periodb.acf:age06_15:sexM                0.01      0.98    -1.95     1.93 1.00     7778     3164
acf_periodc.postMacf:age06_15:sexM          -0.58      0.63    -1.80     0.65 1.00     4705     2901
acf_periodb.acf:age16_25:sexM                0.01      0.96    -1.89     1.90 1.00     6657     2848
acf_periodc.postMacf:age16_25:sexM           0.65      0.53    -0.36     1.69 1.00     4256     3449
acf_periodb.acf:age26_35:sexM               -0.01      1.01    -1.95     1.95 1.00     6234     2832
acf_periodc.postMacf:age26_35:sexM           0.40      0.52    -0.61     1.40 1.00     3754     3322
acf_periodb.acf:age36_45:sexM                0.00      0.98    -1.89     1.88 1.00     7630     2767
acf_periodc.postMacf:age36_45:sexM           0.10      0.55    -0.97     1.20 1.00     4806     3262
acf_periodb.acf:age46_55:sexM                0.00      0.99    -1.99     1.94 1.00     6639     3139
acf_periodc.postMacf:age46_55:sexM           0.66      0.54    -0.40     1.70 1.00     4437     2911
acf_periodb.acf:age56_65:sexM                0.02      0.97    -1.87     1.92 1.00     7289     2921
acf_periodc.postMacf:age56_65:sexM           0.34      0.57    -0.74     1.46 1.00     4341     3319
acf_periodb.acf:age65P:sexM                  0.04      0.98    -1.86     1.95 1.00     6525     3240
acf_periodc.postMacf:age65P:sexM             0.27      0.60    -0.91     1.46 1.00     4599     3141
y_num:acf_perioda.preMacf:age06_15           0.02      0.04    -0.05     0.10 1.00     1656     2702
y_num:acf_periodb.acf:age06_15               0.15      0.13    -0.11     0.42 1.00     6384     2890
y_num:acf_periodc.postMacf:age06_15          0.08      0.05    -0.02     0.17 1.00     3217     3004
y_num:acf_perioda.preMacf:age16_25           0.12      0.03     0.06     0.19 1.00     1498     2372
y_num:acf_periodb.acf:age16_25               0.25      0.13    -0.01     0.50 1.00     6014     2846
y_num:acf_periodc.postMacf:age16_25         -0.04      0.04    -0.12     0.04 1.00     2736     3384
y_num:acf_perioda.preMacf:age26_35           0.15      0.03     0.08     0.22 1.00     1593     2508
y_num:acf_periodb.acf:age26_35               0.31      0.14     0.05     0.59 1.00     5080     2449
y_num:acf_periodc.postMacf:age26_35          0.02      0.04    -0.06     0.10 1.00     2836     2985
y_num:acf_perioda.preMacf:age36_45           0.17      0.04     0.10     0.24 1.00     1676     2526
y_num:acf_periodb.acf:age36_45               0.40      0.14     0.14     0.67 1.00     6032     3088
y_num:acf_periodc.postMacf:age36_45          0.06      0.04    -0.02     0.14 1.00     2986     3068
y_num:acf_perioda.preMacf:age46_55           0.19      0.04     0.11     0.28 1.00     1857     2753
y_num:acf_periodb.acf:age46_55               0.44      0.13     0.18     0.70 1.00     6515     2608
y_num:acf_periodc.postMacf:age46_55          0.09      0.04     0.01     0.18 1.00     3184     3159
y_num:acf_perioda.preMacf:age56_65           0.17      0.05     0.08     0.27 1.00     2082     2571
y_num:acf_periodb.acf:age56_65               0.39      0.13     0.14     0.64 1.00     6358     3037
y_num:acf_periodc.postMacf:age56_65          0.11      0.05     0.02     0.20 1.00     3033     3210
y_num:acf_perioda.preMacf:age65P             0.23      0.05     0.13     0.33 1.00     2645     2713
y_num:acf_periodb.acf:age65P                 0.43      0.13     0.18     0.68 1.00     7083     3005
y_num:acf_periodc.postMacf:age65P            0.11      0.05     0.02     0.20 1.00     3171     2781
y_num:acf_perioda.preMacf:sexM               0.02      0.04    -0.06     0.09 1.00     1333     2367
y_num:acf_periodb.acf:sexM                  -0.04      0.14    -0.31     0.24 1.00     6215     3021
y_num:acf_periodc.postMacf:sexM             -0.01      0.04    -0.09     0.06 1.00     2254     2895
y_num:acf_perioda.preMacf:age06_15:sexM      0.00      0.05    -0.10     0.10 1.00     1870     2862
y_num:acf_periodb.acf:age06_15:sexM          0.04      0.14    -0.23     0.33 1.00     6489     2838
y_num:acf_periodc.postMacf:age06_15:sexM     0.10      0.06    -0.01     0.21 1.00     3508     2947
y_num:acf_perioda.preMacf:age16_25:sexM     -0.00      0.05    -0.09     0.09 1.00     1633     2322
y_num:acf_periodb.acf:age16_25:sexM          0.06      0.13    -0.21     0.32 1.00     5721     2812
y_num:acf_periodc.postMacf:age16_25:sexM    -0.01      0.05    -0.11     0.09 1.00     3214     3072
y_num:acf_perioda.preMacf:age26_35:sexM     -0.01      0.05    -0.10     0.08 1.00     1558     2600
y_num:acf_periodb.acf:age26_35:sexM          0.05      0.14    -0.23     0.33 1.00     5835     3066
y_num:acf_periodc.postMacf:age26_35:sexM    -0.00      0.05    -0.10     0.09 1.00     2801     2922
y_num:acf_perioda.preMacf:age36_45:sexM     -0.01      0.05    -0.11     0.08 1.00     1678     2542
y_num:acf_periodb.acf:age36_45:sexM          0.00      0.14    -0.26     0.27 1.00     5495     2932
y_num:acf_periodc.postMacf:age36_45:sexM    -0.00      0.05    -0.10     0.10 1.00     3458     3304
y_num:acf_perioda.preMacf:age46_55:sexM     -0.01      0.05    -0.11     0.10 1.00     1708     2607
y_num:acf_periodb.acf:age46_55:sexM         -0.00      0.14    -0.28     0.28 1.00     5719     2840
y_num:acf_periodc.postMacf:age46_55:sexM    -0.06      0.05    -0.17     0.04 1.00     3314     2999
y_num:acf_perioda.preMacf:age56_65:sexM      0.05      0.06    -0.06     0.17 1.00     1993     2399
y_num:acf_periodb.acf:age56_65:sexM          0.07      0.14    -0.19     0.35 1.00     6147     2930
y_num:acf_periodc.postMacf:age56_65:sexM     0.02      0.05    -0.09     0.12 1.00     3245     3092
y_num:acf_perioda.preMacf:age65P:sexM        0.00      0.06    -0.11     0.13 1.00     2469     3062
y_num:acf_periodb.acf:age65P:sexM            0.07      0.14    -0.20     0.34 1.01     5209     3126
y_num:acf_periodc.postMacf:age65P:sexM       0.01      0.06    -0.10     0.12 1.00     3625     2882

Further Distributional Parameters:
      Estimate Est.Error l-95% CI u-95% CI Rhat Bulk_ESS Tail_ESS
shape   202.57     68.03   108.42   370.40 1.00     2430     2563

Draws were sampled using sampling(NUTS). For each parameter, Bulk_ESS
and Tail_ESS are effective sample size measures, and Rhat is the potential
scale reduction factor on split chains (at convergence, Rhat = 1).
plot(m_age_sex)

pp_check(m_age_sex, type='ecdf_overlay')
Using 10 posterior draws for ppc type 'ecdf_overlay' by default.

Summarise posterior

ggsave(here("figures/s12.png"), height=10)
Saving 7 x 10 in image

9.2 Summary of impact of intervention

Calculate summary effects


#Peak
out_age_sex_1 <- crossing(mdata_age_sex %>% 
                      select(y_num, age, sex) %>%
                      filter(y_num == 8),
                      acf_period = c("a. pre-acf", "b. acf"))

peak_draws_age_sex <- add_epred_draws(newdata = out_age_sex_1,
                  object = m_age_sex) %>%
    group_by(.draw, age, sex) %>%
    summarise(estimate = last(.epred)/first(.epred)) %>%
    ungroup() %>%
    mutate(measure = "RR.peak")
`summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
peak_summary_age_sex <- peak_draws_age_sex %>%
    group_by(age, sex) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.peak")


#Level
 
out_age_sex_2 <- crossing(mdata_age_sex %>% 
                      select(y_num, age, sex) %>%
                      filter(y_num == 9),
                      acf_period = c("a. pre-acf", "c. post-acf"))
  
level_draws_age_sex <- add_epred_draws(newdata = out_age_sex_2,
                  object = m_age_sex) %>%
    arrange(y_num, .draw) %>%
    group_by(.draw, age, sex) %>%
    summarise(estimate = last(.epred)/first(.epred)) %>%
    ungroup() %>%
    mutate(measure = "RR.level")
`summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
level_summary_age_sex <- level_draws_age_sex %>%
    group_by(age, sex) %>%
    mean_qi(estimate) %>%
    mutate(measure = "RR.level")

#Slope

out_age_sex_3 <- crossing(mdata_age_sex %>% 
                      select(y_num, age, sex) %>%
                      filter(y_num %in% c(9,14)),
                    acf_period = c("a. pre-acf", "c. post-acf"))
  
slope_draws_age_sex <- add_epred_draws(newdata = out_age_sex_3,
                  object = m_age_sex) %>%
        arrange(y_num) %>%
        ungroup() %>%
        group_by(.draw, y_num, age, sex) %>%
        summarise(slope = last(.epred)/first(.epred)) %>%
        ungroup() %>%
        group_by(.draw, age, sex) %>%
        summarise(estimate = last(slope)/first(slope)) %>%
        mutate(measure = "RR.slope")
`summarise()` has grouped output by '.draw', 'y_num', 'age'. You can override using the `.groups` argument.`summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
slope_summary_age_sex <- slope_draws_age_sex %>%
     group_by(age, sex) %>%
      median_qi(estimate) %>%
      mutate(measure = "RR.slope")

Numerical summary of these summary results


bind_rows(
  peak_summary_age_sex, level_summary_age_sex, slope_summary_age_sex
) %>%
  mutate(across(c(estimate:.upper), number, accuracy=0.01)) %>%
  select(measure, everything()) %>%
  datatable()
NA
NA
NA

As a figure


peak_g_age_sex <- peak_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

#level plot
level_g_age_sex <- level_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

#slope plot
slope_g_age_sex <- slope_summary_age_sex %>%
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_hline(aes(yintercept=1), linetype=2)+
  geom_pointrange(aes(x=age, y=estimate, ymin=.lower, ymax=.upper, group=sex, colour=sex, shape=sex),
                  position = position_dodge(width = 0.5)) +
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  labs(x="",
       y="Relative rate (95% UI)") +
  theme_ggdist() +
  theme(legend.position = "bottom",
        panel.border = element_rect(colour = "grey78", fill=NA))

9.3 Compared to counterfactual


counterfact_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(year, age, sex, .draw, .epred_counterf = .epred)
Adding missing grouping variables: `year2`, `y_num`, `acf_period`, `.row`
  
#Calcuate predicted number of cases per draw, then summarise.
post_change_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      ungroup() %>%
      select(year, age, sex, .draw, .epred) 
  
#for the overall period
counterfact_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex) %>%
                                    mutate(acf_period = "a. pre-acf")) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred)  %>%
      group_by(age, sex, .draw) %>%
      summarise(.epred_counterf = sum(.epred)) %>%
      mutate(year = "Overall (1958-1963)")
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by 'age', 'sex'. You can override using the `.groups` argument.
  
#Calcuate incidence per draw, then summarise.
post_change_overall_age_sex <-
      add_epred_draws(object = m_age_sex,
                      newdata = mdata_age_sex %>%
                                    select(year, year2, y_num, age, sex, acf_period)) %>%
      filter(year>1957) %>%
      select(age, sex, .draw, .epred) %>%
      group_by(.draw, age, sex) %>%
      summarise(.epred = sum(.epred)) 
Adding missing grouping variables: `year`, `year2`, `y_num`, `acf_period`, `.row``summarise()` has grouped output by '.draw', 'age'. You can override using the `.groups` argument.
  
counter_post_overall_age_sex <-
  left_join(counterfact_overall_age_sex, post_change_overall_age_sex) %>%
    mutate(cases_averted = .epred_counterf-.epred,
           pct_change = (.epred - .epred_counterf)/.epred_counterf) %>%
    group_by(age, sex) %>%
    mean_qi(cases_averted, pct_change) %>%
    ungroup() %>%
    mutate(year = "Overall (1958-1963)") 
Joining with `by = join_by(age, sex, .draw)`
age_sex_txt <- counter_post_overall_age_sex %>%
  mutate(across(c(cases_averted:cases_averted.upper), number_format(accuracy = 0.1, big.mark = ","))) %>%
  mutate(across(c(pct_change:pct_change.upper), percent, accuracy=0.1)) %>%
  transmute(year = as.character(year),
            sex = sex,
            age = age,
            cases_averted = glue::glue("{cases_averted}\n({cases_averted.lower} to {cases_averted.upper})"),
            pct_change = glue::glue("{pct_change}\n({pct_change.lower} to {pct_change.upper})"))


age_sex_txt %>% datatable()
NA
NA

counterfactual_g_age_sex <- counter_post_overall_age_sex %>% 
  mutate(sex = case_when(sex=="M" ~ "Male",
                         sex=="F" ~ "Female")) %>%
  mutate(age = case_when(age=="00_05" ~ "0 to 5y",
                         age=="06_15" ~ "06 to 15y",
                         age=="16_25" ~ "16 to 25y",
                         age=="26_35" ~ "26 to 35y",
                         age=="36_45" ~ "36 to 45y",
                         age=="46_55" ~ "46 to 55y",
                         age=="56_65" ~ "56 to 65y",
                         age=="65+" ~ "65 & up y")) %>%
  ggplot() +
  geom_pointrange(aes(x = age, y=cases_averted, ymin=cases_averted.lower, ymax=cases_averted.upper, colour=sex, shape=sex), position=position_dodge(width=0.5)) + 
  scale_colour_manual(values = c("#CD7AC5", "cadetblue3"), name="") +
  scale_shape(name="") +
  scale_y_continuous(labels = comma) +
  labs(x="",
       y="Number (95% UI)",
       colour="") +
  theme_ggdist() +
  theme(panel.border = element_rect(colour = "grey78", fill=NA),
        legend.position = "bottom")

counterfactual_g_age_sex

Join together for Figure 3.


(peak_g_age_sex + level_g_age_sex) / (slope_g_age_sex + counterfactual_g_age_sex) + plot_annotation(tag_levels = "A") + plot_layout(guides = "collect") & theme(legend.position = "bottom")

ggsave(here("figures/f3.png"), width = 12, height=8)

NA
NA

10 Division model

Was uptake of CXR at division level associated with greated impact?

{r} # # m_division <- brm( # cases ~ 1 + y_num*acf_period + (1 + y_num*acf_period | ward) + offset(log(population_without_inst_ship)), # data = mdata, # family = negbinomial(), # seed = 1234, # chains = 4, cores = 4, # prior = prior(normal(0,1), class = Intercept) + # prior(gamma(0.01, 0.01), class = shape) + # prior(normal(0, 1), class = b) + # prior(exponential(1), class=sd) + # prior(lkj(4), class=cor), # control = list(adapt_delta = 0.9)) # #

LS0tCnRpdGxlOiAiR2xhc2dvdyBUQiBBQ0YiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMjIyAxLiBMaWJyYXJpZXMgYW5kIGZ1bmN0aW9ucwoKIyMjIyAxLjEgTGlicmFyaWVzCgpMb2FkIHRoZSByZXF1aXJlZCBsaWJyYXJpZXMuCgpgYGB7ciwgbWVzc2FnZT1GLCB3YXJuaW5nPUZ9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHNmKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkocmVhZHhsKQpsaWJyYXJ5KHNjYWxlcykKbGlicmFyeShEVCkKbGlicmFyeShicm1zKQpsaWJyYXJ5KHRpZHliYXllcykKbGlicmFyeShwYXRjaHdvcmspCmxpYnJhcnkobWFyZ2luYWxlZmZlY3RzKQpsaWJyYXJ5KGdncmVwZWwpCmxpYnJhcnkoc2NpY28pCmxpYnJhcnkoZ2dkZW5zaXR5KQpsaWJyYXJ5KGdncHVicikKbGlicmFyeSh1bml0cykKbGlicmFyeShnbHVlKQpsaWJyYXJ5KGdnaDR4KQoKYGBgCgojIyMjIDEuMiBIZWxwZXIgZnVuY3Rpb25zCgpGdW5jdGlvbnMgdGhhdCB3ZSB3aWxsIHVzZSB0aHJvdWdob3V0IHRoZSBzY3JpcHQKCmBgYHtyfQojbGFiZWxsZXIgZm9yIHllYXJzCnllYXJfbGFiZWxzIDwtIGMoMTk1MDoxOTYzKQoKI1RoZSBHbGFzZ293IG1hc3MgbWludXR1cmUgY2hlc3QgWC1yYXkgY2FtcGFpZ24gaGFwcGVuZWQgYmV0d2VlbiAxMXRoIE1hcmNoIGFuZCAxMnRoIEFwcmlsIDE5NTcKI1NlZ21lbnQgZm9yIGdyYXBocyB0byBtYXRjaCBBQ0YgcGVyaW9kCmFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCmFjZl9lbmQgPC0gZGVjaW1hbF9kYXRlKHltZCgiMTk1Ny0wNC0xMiIpKQoKCmBgYAoKRnVuY3Rpb24gZm9yIGNvdW50ZXJmYWN0dWFsIHBsb3RzCgpgYGB7cn0KCgpwbG90X2NvdW50ZXJmYWN0dWFsIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBvdXRjb21lLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYSwuLi4pewogIAogICNsYWJlbGxlciBmb3IgeWVhcnMKICB5ZWFyX2xhYmVscyA8LSBjKDE5NTA6MTk2NCkgI2V4dHJhIHllYXIgZm9yIHRoZSBleHRhbnQgb2YgdGhlIHgtYXhpcwoKICAjVGhlIEdsYXNnb3cgbWFzcyBtaW51dHVyZSBjaGVzdCBYLXJheSBjYW1wYWlnbiBoYXBwZW5lZCBiZXR3ZWVuIDExdGggTWFyY2ggYW5kIDEydGggQXByaWwgMTk1NwogICNTZWdtZW50IGZvciBncmFwaHMgdG8gbWF0Y2ggQUNGIHBlcmlvZAogIGFjZl9zdGFydCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTAzLTExIikpCiAgYWNmX2VuZCA8LSBkZWNpbWFsX2RhdGUoeW1kKCIxOTU3LTA0LTEyIikpCgogIHN1bW1hcnkgPC0ge3ttb2RlbF9kYXRhfX0gJT4lCiAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tvdXRjb21lfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgYWRkX2VwcmVkX2RyYXdzKHt7bW9kZWx9fSwgcmVfZm9ybXVsYT17e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICBtZWFuX3FpKCkgJT4lCiAgICBtdXRhdGUoLmVwcmVkX2luYyA9IC5lcHJlZC97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDAsCiAgICAgICAgICAuZXByZWRfaW5jLmxvd2VyID0gLmVwcmVkLmxvd2VyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgIC5lcHJlZF9pbmMudXBwZXIgPSAuZXByZWQudXBwZXIve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAlPiUKICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKCgoKICAjY3JlYXRlIHRoZSBjb3VudGVyZmFjdHVhbCAobm8gaW50ZXJ2ZW50aW9uKSwgYW5kIHN1bW1hcmlzZQogIAogIGNvdW50ZXJmYWN0IDwtCiAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0ge3ttb2RlbH19LAogICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCB7e291dGNvbWV9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIiksIHJlX2Zvcm11bGE9e3tyZV9mb3JtdWxhfX0pICU+JQogICAgZ3JvdXBfYnkoeWVhcjIsIGFjZl9wZXJpb2QsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgbWVhbl9xaSgpICU+JQogICAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwLAogICAgICAgICAuZXByZWRfaW5jLmxvd2VyID0gLmVwcmVkLmxvd2VyL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwKICAgICAgICAgLmVwcmVkX2luYy51cHBlciA9IC5lcHJlZC51cHBlci97e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSoxMDAwMDApICU+JQogICAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oYWNmX3BlcmlvZD09ImEuIHByZS1hY2YiIH4gIkJlZm9yZSBJbnRlcnZlbnRpb24iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdCBJbnRlcnZlbnRpb24iKSkKICAKCgogICNwbG90IHRoZSBpbnRlcnZlbnRpb24gZWZmZWN0CnAgPC0gc3VtbWFyeSAlPiUKICAgIGRyb3BsZXZlbHMoKSAlPiUKICAgIGdncGxvdCgpICsKICAgIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0LCBsaW5ldHlwZT0iTWFzcyBDWFIgc2NyZWVuaW5nIGludGVydmVudGlvbiIpKSArCiAgICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQsIGxpbmV0eXBlPSJNYXNzIENYUiBzY3JlZW5pbmcgaW50ZXJ2ZW50aW9uIikpICsKICAgIGdlb21fcmliYm9uKGFlcyh5bWluPS5lcHJlZF9pbmMubG93ZXIsIHltYXg9LmVwcmVkX2luYy51cHBlciwgeD15ZWFyMiwgZ3JvdXAgPSBhY2ZfcGVyaW9kLCBmaWxsPWFjZl9wZXJpb2QpLCBhbHBoYT0wLjUpICsKICAgIGdlb21fcmliYm9uKGRhdGEgPSBjb3VudGVyZmFjdCAlPiUgZmlsdGVyKHllYXI+PTE5NTYpLCAKICAgICAgICAgICAgICAgIGFlcyh5bWluPS5lcHJlZF9pbmMubG93ZXIsIHltYXg9LmVwcmVkX2luYy51cHBlciwgeD15ZWFyMiwgZmlsbD0iQ291bnRlcmZhY3R1YWwiKSwgYWxwaGE9MC41KSArCiAgICBnZW9tX2xpbmUoZGF0YSA9IGNvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5PS5lcHJlZF9pbmMsIHg9eWVhcjIsIGNvbG91cj0iQ291bnRlcmZhY3R1YWwiKSkgKwogICAgZ2VvbV9saW5lKGFlcyh5PS5lcHJlZF9pbmMsIHg9eWVhcjIsIGdyb3VwPWFjZl9wZXJpb2QsICBjb2xvdXI9YWNmX3BlcmlvZCkpICsKICAgIGdlb21fcG9pbnQoZGF0YSA9IHt7bW9kZWxfZGF0YX19ICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJQcmUtQUNGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYi4gYWNmIiB+ICJBQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdC1BQ0YiKSksIAogICAgICAgICAgICAgICBhZXMoeT17e291dGNvbWV9fSwgeD15ZWFyMiwgc2hhcGU9ZmN0X3JlbGV2ZWwoYWNmX3BlcmlvZCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJQcmUtQUNGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICJBQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlBvc3QtQUNGIikpLCBzaXplPTIpICsKICAgIHRoZW1lX2dyZXkoKSArCiAgICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hLCBsaW1pdHMgPWMoMCw0MDApKSArCiAgICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9Ik1vZGVsIGVzdGltYXRlczoiLCBuYS50cmFuc2xhdGUgPSBGKSArCiAgICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNERTBEOTIiLCAiZ3JleTUwIiwgIiM0RDZDRkEiKSAsIG5hbWU9Ik1vZGVsIGVzdGltYXRlczoiLCBuYS50cmFuc2xhdGUgPSBGKSArCiAgICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lPSJFbXBpcmljYWwgZGF0YSAocGVyaW9kKToiLCBuYS50cmFuc2xhdGUgPSBGKSArCiAgICBzY2FsZV9saW5ldHlwZV9tYW51YWwodmFsdWVzID0gMiwgbmFtZT0iIikgKwogICAgbGFicygKICAgICAgeCA9ICIiLAogICAgICB5ID0gIkNOUiAocGVyIDEwMCwwMDApIgogICAgKSArCiAgICBndWlkZXMoeCA9ICJheGlzX3RydW5jYXRlZCIsIHkgPSAiYXhpc190cnVuY2F0ZWQiKSArCiAgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICAgIGxlZ2VuZC5ib3g9InZlcnRpY2FsIiwgCiAgICAgICAgICB0ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgICAgYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoc2l6ZT0xMCwgYW5nbGUgPSA5MCwgaGp1c3Q9MSwgdmp1c3Q9MC41KSwKICAgICAgICAgIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemU9MTApLAogICAgICAgICAgbGVnZW5kLnNwYWNpbmcueSA9IHVuaXQoMC4xLCAnY20nKSwKICAgICAgICAgIGF4aXMubGluZSA9IGVsZW1lbnRfbGluZShjb2xvdXIgPSAiYmxhY2siKSkgCgogICAgZmFjZXRfdmFycyA8LSB2YXJzKC4uLikKCiAgaWYgKGxlbmd0aChmYWNldF92YXJzKSAhPSAwKSB7CiAgICBwIDwtIHAgKyBmYWNldF93cmFwKGZhY2V0X3ZhcnMpCiAgfQogIHAKCn0KCmBgYAoKRnVuY3Rpb24gZm9yIGNhbGN1bGF0aW5nICBtZWFzdXJlcyBvZiBjaGFuZ2Ugb3ZlciB0aW1lIChSUi5wZWFrLCBSUi5sZXZlbCwgUlIuc2xvcGUpCgoKYGBge3J9CgpzdW1tYXJpc2VfY2hhbmdlIDwtIGZ1bmN0aW9uKG1vZGVsX2RhdGEsIG1vZGVsLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yLCBncm91cGluZ192YXIgPSBOVUxMLCByZV9mb3JtdWxhID0gTlVMTCkgewogIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnBlYWsKICAjaS5lLiByZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTcgdnMuIGNvdW50ZXJmYWN0dWFsIHRyZW5kIGZvciAxOTU3CiAgCiAgZ3JvdXBpbmdfdmFyIDwtIGVucXVvKGdyb3VwaW5nX3ZhcikKICAKICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIAogICAgI21ha2UgdGhlIHByZWRpY3Rpb24gbWF0cml4LCBjb25kaXRpb25hbCBvbiB3aGV0aGVyIHdlIHdhbnQgcmFuZG9tIGVmZmVjdHMgaW5jbHVkZWQgb3Igbm90LgogICAgb3V0IDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0sICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA4KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJiLiBhY2YiKQogICAgKQogIH0gZWxzZSB7CiAgICAKICAgIG91dCA8LSBjcm9zc2luZyh7e21vZGVsX2RhdGF9fSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHlfbnVtKSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA4KSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJiLiBhY2YiKQogICAgKQogIH0KICAKICBwZWFrX2RyYXdzIDwtIGFkZF9lcHJlZF9kcmF3cyhuZXdkYXRhID0gb3V0LAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICBtdXRhdGUoZXByZWRfY25yID0gLmVwcmVkL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGdyb3VwX2J5KC5kcmF3LCAhIWdyb3VwaW5nX3ZhcikgJT4lCiAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KGVwcmVkX2NucikvZmlyc3QoZXByZWRfY25yKSkgJT4lCiAgICB1bmdyb3VwKCkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5wZWFrIikKICAKICBwZWFrX3N1bW1hcnkgPC0gcGVha19kcmF3cyAlPiUKICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIG1lYW5fcWkoZXN0aW1hdGUpICU+JQogICAgbXV0YXRlKG1lYXN1cmUgPSAiUlIucGVhayIpCiAgCiAgCiAgI2Z1bmN0aW9ucyBmb3IgY2FsY3VsYXRpbmcgUlIubGV2ZWwKICAjaS5lLiByZWxhdGl2ZSBjYXNlIG5vdGlmaWNhdGlvbiByYXRlIGluIDE5NTggdnMuIGNvdW50ZXJmYWN0dWFsIHRyZW5kIGZvciAxOTU4CiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDIgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9IGVsc2UgewogICAgCiAgICBvdXQyIDwtIGNyb3NzaW5nKHt7bW9kZWxfZGF0YX19ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgeV9udW0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDkpLAogICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikKICAgICkKICB9CiAgCiAgICBsZXZlbF9kcmF3cyA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dDIsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgIGFycmFuZ2UoeV9udW0sIC5kcmF3KSAlPiUKICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKICAKICBsZXZlbF9zdW1tYXJ5IDwtIGxldmVsX2RyYXdzICU+JQogICAgZ3JvdXBfYnkoISFncm91cGluZ192YXIpICU+JQogICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5sZXZlbCIpCiAgICAKICAgIAogICNmdW5jdGlvbnMgZm9yIGNhbGN1bGF0aW5nIFJSLnNsb3BlCiAgI2kuZS4gcmVsYXRpdmUgY2hhbmdlIGluIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgaW4gMTk1OC0xOTYzIHZzLiBjb3VudGVyZmFjdHVhbCB0cmVuZCBmb3IgMTk1OS0xOTYzCiAgCiAgICBpZiAoIWlzLm51bGwoe3tncm91cGluZ192YXJ9fSkpIHsKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKQogICAgKQogIH0gZWxzZSB7CiAgICAKICAgIG91dDMgPC0gY3Jvc3Npbmcoe3ttb2RlbF9kYXRhfX0gJT4lIAogICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB5X251bSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoeV9udW0gJWluJSBjKDksMTQpKSwKICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kID0gYygiYS4gcHJlLWFjZiIsICJjLiBwb3N0LWFjZiIpCiAgICApCiAgfQogIAogICAgc2xvcGVfZHJhd3MgPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXQzLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgICAgYXJyYW5nZSh5X251bSkgJT4lCiAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgIG11dGF0ZShlcHJlZF9jbnIgPSAuZXByZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApICU+JQogICAgICAgIGdyb3VwX2J5KC5kcmF3LCB5X251bSwgISFncm91cGluZ192YXIpICU+JQogICAgICAgIHN1bW1hcmlzZShzbG9wZSA9IGxhc3QoZXByZWRfY25yKS9maXJzdChlcHJlZF9jbnIpKSAlPiUKICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgZ3JvdXBfYnkoLmRyYXcsICEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KHNsb3BlKS9maXJzdChzbG9wZSkpICU+JQogICAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAKICBzbG9wZV9zdW1tYXJ5IDwtIHNsb3BlX2RyYXdzICU+JQogICAgIGdyb3VwX2J5KCEhZ3JvdXBpbmdfdmFyKSAlPiUKICAgICAgbWVhbl9xaShlc3RpbWF0ZSkgJT4lCiAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAgIAogICNnYXRoZXIgYWxsIHRoZSByZXN1bHRzIGludG8gYSBuYW1lZCBsaXN0CiAgICBsc3QocGVha19kcmF3cz1wZWFrX2RyYXdzLCBwZWFrX3N1bW1hcnk9cGVha19zdW1tYXJ5LCAKICAgICAgICBsZXZlbF9kcmF3cz1sZXZlbF9kcmF3cywgbGV2ZWxfc3VtbWFyeT1sZXZlbF9zdW1tYXJ5LCAKICAgICAgICBzbG9wZV9kcmF3cz1zbG9wZV9kcmF3cywgc2xvcGVfc3VtbWFyeT1zbG9wZV9zdW1tYXJ5KQogIAp9CgpgYGAKCgpGdW5jdGlvbiBmb3IgY2FsY3VsYXRpbmcgZGlmZmVyZW5jZSBmcm9tIGNvdW50ZXJmYWN0dWFsCgpgYGB7cn0KCmNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbCA8LSBmdW5jdGlvbihtb2RlbF9kYXRhLCBtb2RlbCwgcG9wdWxhdGlvbl9kZW5vbWluYXRvciwgZ3JvdXBpbmdfdmFyPU5VTEwsIHJlX2Zvcm11bGE9TkEpewogIAogICNlZmZlY3QgdnMuIGNvdW50ZXJmYWN0dWFsCiAgY291bnRlcmZhY3QgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIiksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywgeWVhciwge3tncm91cGluZ192YXJ9fSwgYWNmX3BlcmlvZCkgJT4lCiAgICAgIG11dGF0ZSguZXByZWRfaW5jX2NvdW50ZXJmID0gLmVwcmVkL3t7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19KjEwMDAwMCwgLmVwcmVkX2NvdW50ZXJmPS5lcHJlZCkgICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3QoeWVhciwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIC5kcmF3LCAuZXByZWRfY291bnRlcmYsIC5lcHJlZF9pbmNfY291bnRlcmYsIHt7Z3JvdXBpbmdfdmFyfX0pCiAgCiAgI0NhbGN1YXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlIDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSB7e21vZGVsfX0sCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0ge3ttb2RlbF9kYXRhfX0gJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIHt7cG9wdWxhdGlvbl9kZW5vbWluYXRvcn19LCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSwKICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB7e3JlX2Zvcm11bGF9fSkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCB5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19LCBhY2ZfcGVyaW9kKSAlPiUKICAgICAgbXV0YXRlKC5lcHJlZF9pbmMgPSAuZXByZWQve3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0qMTAwMDAwKSAgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCB7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwge3tncm91cGluZ192YXJ9fSwgLmRyYXcsIC5lcHJlZCwgLmVwcmVkX2luYywge3tncm91cGluZ192YXJ9fSkgCiAgCiAgI2ZvciB0aGUgb3ZlcmFsbCBwZXJpb2QKICAgIGNvdW50ZXJmYWN0X292ZXJhbGwgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIiksCiAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0ge3tyZV9mb3JtdWxhfX0pICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIGZpbHRlcih5ZWFyPjE5NTcpICU+JQogICAgICB1bmdyb3VwKCkgJT4lCiAgICAgIHNlbGVjdCh7e3BvcHVsYXRpb25fZGVub21pbmF0b3J9fSwgLmRyYXcsIC5lcHJlZCwge3tncm91cGluZ192YXJ9fSkgICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWRfY291bnRlcmYgPSBzdW0oLmVwcmVkKSkgCiAgCiAgI0NhbGN1YXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgogIHBvc3RfY2hhbmdlX292ZXJhbGwgPC0KICAgICAgYWRkX2VwcmVkX2RyYXdzKG9iamVjdCA9IHt7bW9kZWx9fSwKICAgICAgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSB7e21vZGVsX2RhdGF9fSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwge3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIGFjZl9wZXJpb2QpLAogICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IHt7cmVfZm9ybXVsYX19KSAlPiUKICAgICAgZ3JvdXBfYnkoLmRyYXcsIHt7Z3JvdXBpbmdfdmFyfX0pICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgdW5ncm91cCgpICU+JQogICAgICBzZWxlY3Qoe3twb3B1bGF0aW9uX2Rlbm9taW5hdG9yfX0sIHt7Z3JvdXBpbmdfdmFyfX0sIC5kcmF3LCAuZXByZWQpICU+JQogICAgICBncm91cF9ieSguZHJhdywge3tncm91cGluZ192YXJ9fSkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCiAgCmNvdW50ZXJfcG9zdCA8LQogIGxlZnRfam9pbihjb3VudGVyZmFjdCwgcG9zdF9jaGFuZ2UpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYsCiAgICAgICAgICAgZGlmZl9pbmMxMDBrID0gLmVwcmVkX2luYyAtIC5lcHJlZF9pbmNfY291bnRlcmYsCiAgICAgICAgICAgcnJfaW5jMTAwayA9IC5lcHJlZF9pbmMvLmVwcmVkX2luY19jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSwgZGlmZl9pbmMxMDBrLCBycl9pbmMxMDBrKSAlPiUKICAgIHVuZ3JvdXAoKQoKY291bnRlcl9wb3N0X292ZXJhbGwgPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbCwgcG9zdF9jaGFuZ2Vfb3ZlcmFsbCkgJT4lCiAgICBtdXRhdGUoY2FzZXNfYXZlcnRlZCA9IC5lcHJlZF9jb3VudGVyZi0uZXByZWQsCiAgICAgICAgICAgcGN0X2NoYW5nZSA9ICguZXByZWQgLSAuZXByZWRfY291bnRlcmYpLy5lcHJlZF9jb3VudGVyZikgJT4lCiAgICBncm91cF9ieSh7e2dyb3VwaW5nX3Zhcn19KSAlPiUKICAgIG1lYW5fcWkoY2FzZXNfYXZlcnRlZCwgcGN0X2NoYW5nZSkgJT4lCiAgICB1bmdyb3VwKCkKCmxzdChjb3VudGVyX3Bvc3QsIGNvdW50ZXJfcG9zdF9vdmVyYWxsKQoKfQoKCmBgYAoKRnVuY3Rpb24gZm9yIHRpZHlpbmcgdXAgY291bnRlcmZhY3R1YWxzIChtb3N0bHkgZm9yIG1ha2luZyBuaWNlIHRhYmxlcykKCmBgYHtyfQoKdGlkeV9jb3VudGVyZmFjdHVhbHMgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZGF0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoeWVhciA9IGFzLmNoYXJhY3Rlcih5ZWFyKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWU6OmdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSwKICAgICAgICAgICAgZGlmZl9pbmMgPSBnbHVlOjpnbHVlKCJ7ZGlmZl9pbmMxMDBrfSAoe2RpZmZfaW5jMTAway5sb3dlcn0gdG8ge2RpZmZfaW5jMTAway51cHBlcn0pIiksCiAgICAgICAgICAgIHJyX2luYyA9IGdsdWU6OmdsdWUoIntycl9pbmMxMDBrfSAoe3JyX2luYzEwMGsubG93ZXJ9IHRvIHtycl9pbmMxMDBrLnVwcGVyfSkiKSkKfQoKCnRpZHlfY291bnRlcmZhY3R1YWxzX292ZXJhbGwgPC0gZnVuY3Rpb24oZGF0YSl7CiAgZGF0YSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZSh5ZWFyID0gYXMuY2hhcmFjdGVyKHllYXIpLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9ICh7Y2FzZXNfYXZlcnRlZC5sb3dlcn0gdG8ge2Nhc2VzX2F2ZXJ0ZWQudXBwZXJ9KSIpLAogICAgICAgICAgICBwY3RfY2hhbmdlID0gZ2x1ZTo6Z2x1ZSgie3BjdF9jaGFuZ2V9ICh7cGN0X2NoYW5nZS5sb3dlcn0gdG8ge3BjdF9jaGFuZ2UudXBwZXJ9KSIpKQp9CgpgYGAKCgoKIyMjIDIuIERhdGEKCkltcG9ydCBkYXRhc2V0cyBmb3IgYW5hbHlzaXMKCiMjIyMgMi4xIFNoYXBlZmlsZXMKCk1ha2UgYSBtYXAgb2YgR2xhc2dvdyB3YXJkcwoKYGBge3J9CgpnbGFzZ293X3dhcmRzXzE5NTEgPC0gc3RfcmVhZChoZXJlKCJtYXBwaW5nL2dsYXNnb3dfd2FyZHNfMTk1MS5nZW9qc29uIikpCgpgYGAKCmBgYHtyfQoKI3JlYWQgaW4gU2NvdGxhbmQgYm91bmRhcnkKc2NvdGxhbmQgPC0gc3RfcmVhZChoZXJlKCJtYXBwaW5nL1Njb3RsYW5kX2JvdW5kYXJ5L1Njb3RsYW5kIGJvdW5kYXJ5LnNocCIpKQoKI21ha2UgYSBib3VuZGluZyBib3ggZm9yIEdsYXNnb3cKYmJveCA8LSBzdF9iYm94KGdsYXNnb3dfd2FyZHNfMTk1MSkgfD4gc3RfYXNfc2ZjKCkKCiNwbG90IHNjb3RsYW5kIHdpdGggYSBib3VuZGluZyBib3ggYXJvdW5kIHRoZSBDaXR5IG9mIEdsYXNnb3cKc2NvdGxhbmRfd2l0aF9iYm94IDwtIGdncGxvdCgpICsKICBnZW9tX3NmKGRhdGEgPSBzY290bGFuZCwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIGdlb21fc2YoZGF0YSA9IGJib3gsIGNvbG91ciA9ICIjQzYwQzMwIiwgZmlsbD0iYW50aXF1ZXdoaXRlIikgKwogIHRoZW1lX3ZvaWQoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICIjRUFGN0ZBIiwgc2l6ZSA9IDAuMykpCgojcGxvdCB0aGUgd2FyZHMKI25vdGUgd2UgdGlkeSB1cCBzb21lIG5hbWVzIHRvIGZpdCBvbiBtYXAKZ2xhc2dvd193YXJkX21hcCA8LSBnbGFzZ293X3dhcmRzXzE5NTEgJT4lCiAgbXV0YXRlKHdhcmQgPSBjYXNlX3doZW4od2FyZD09IlNoZXR0bGVzdG9uIGFuZCBUb2xsY3Jvc3MiIH4gIlNoZXR0bGVzdG9uIGFuZFxuVG9sbGNyb3NzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB3YXJkPT0iUGFydGljayAoV2VzdCkiIH4gIlBhcnRpY2tcbihXZXN0KSIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgd2FyZD09IlBhcnRpY2sgKEVhc3QpIiB+ICJQYXJ0aWNrXG4oRWFzdCkiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJOb3J0aCBLZWx2aW4iIH4gIk5vcnRoXG5LZWx2aW4iLAogICAgICAgICAgICAgICAgICAgICAgICAgIHdhcmQ9PSJLaW5uaW5nIFBhcmsiIH4gIktpbm5pbmdcblBhcmsiLAogICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiB3YXJkKSkgJT4lCiAgCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9ZGl2aXNpb24pKSArCiAgZ2VvbV9zZl9sYWJlbChhZXMobGFiZWwgPSB3YXJkKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siKSArCiAgI3NjYWxlX2NvbG91cl9pZGVudGl0eSgpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJDaXR5IG9mIEdsYXNnb3cgRGl2aXNpb24iKSArCiAgdGhlbWVfZ3JleSgpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSIiLAogICAgICAgZmlsbD0iRGl2aXNpb24iKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BLCBsaW5ld2lkdGggPSAwLjUpLAogICAgICAgIHBhbmVsLmJhY2tncm91bmQgPSBlbGVtZW50X3JlY3QoZmlsbCA9ICJhbnRpcXVld2hpdGUiLCBzaXplID0gMC4zKSwKICAgICAgICBwYW5lbC5ncmlkLm1ham9yID0gZWxlbWVudF9saW5lKGNvbG9yID0gImdyZXk3OCIpKSArCiAgZ3VpZGVzKGZpbGw9Z3VpZGVfbGVnZW5kKHRpdGxlLnBvc2l0aW9uID0gInRvcCIsIHRpdGxlLmhqdXN0ID0gMC41LCB0aXRsZS50aGVtZSA9IGVsZW1lbnRfdGV4dChmYWNlPSJib2xkIikpKQoKI2FkZCB0aGUgbWFwIG9mIHNjb3RsYW5kIGFzIGFuIGluc2V0CmdsYXNnb3dfd2FyZF9tYXAgKyBpbnNldF9lbGVtZW50KHNjb3RsYW5kX3dpdGhfYmJveCwgMC43NSwgMCwgMSwgMC40KQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczEucG5nIiksIGhlaWdodD0xMCwgd2lkdGggPSAxMikKCgpgYGAKCkNhbGN1bGF0ZSBhcmVhcyBwZXIgZ2VvZ3JhcGhpY2FsIHVuaXQKCmBgYHtyfQpzZl91c2VfczIoRkFMU0UpICNodHRwczovL2dpdGh1Yi5jb20vci1zcGF0aWFsL3NmL2lzc3Vlcy8xNzYyCgpnbGFzZ293X3dhcmRzXzE5NTEgPC0gZ2xhc2dvd193YXJkc18xOTUxICU+JQogIG11dGF0ZShhcmVhID0gc3RfYXJlYShnbGFzZ293X3dhcmRzXzE5NTEpKQoKCmdsYXNnb3dfd2FyZHNfMTk1MSRhcmVhX2ttIDwtIHVuaXRzOjpzZXRfdW5pdHMoZ2xhc2dvd193YXJkc18xOTUxJGFyZWEsIGttXjIpCgoKYGBgCgoKTWFrZSBkaXZpc2lvbiBzaGFwZSBmaWxlcywgYW5kIGNhbGN1bGF0ZSBhcmVhCihzdG9wcGVkIHdvcmtpbmcsIG5lZWQgdG8gZml4ISkKCmBgYHtyfQoKIyBnbGFzZ293X2RpdmlzaW9uc18xOTUxIDwtIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKIyAgIGdyb3VwX2J5KGRpdmlzaW9uKSAlPiUgCiMgICBzdW1tYXJpemUoZ2VvbWV0cnkgPSBzdF91bmlvbihnZW9tZXRyeSkpICU+JQojICAgbm5nZW86OnN0X3JlbW92ZV9ob2xlcygpICU+JQojICAgbXV0YXRlKGFyZWEgPSBzdF9hcmVhKGdsYXNnb3dfZGl2aXNpb25zXzE5NTEpKQojIAojIGdsYXNnb3dfZGl2aXNpb25zXzE5NTEkYXJlYV9rbSA8LSB1bml0czo6c2V0X3VuaXRzKGdsYXNnb3dfZGl2aXNpb25zXzE5NTEkYXJlYSwga21eMikKCgpgYGAKCgojIyMgMy4gRGVub21pbmF0b3JzCgpMb2FkIGluIHRoZSBkYXRhc2V0cyBmb3IgZGVub25vbWlhdG9ycywgYW5kIGNoZWNrIGZvciBjb25zaXN0ZW5jeS4KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzIDwtIHJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gIm92ZXJhbGxfcG9wdWxhdGlvbiIpCgpvdmVyYWxsX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKI3NoaWZ0IHllYXIgdG8gbWlkcG9pbnQKb3ZlcmFsbF9wb3BzIDwtIG92ZXJhbGxfcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmBgYAoKTm90ZSwgd2UgaGF2ZSB0aHJlZSBwb3B1bGF0aW9uIGVzdGltYXRlczoKCjEuIFBvcHVsYXRpb24gd2l0aG91dCBpbnN0aXR1dGlvbmFsaXNlZCBwZW9wbGUgb3IgcGVvcGxlIGluIHNoaXBwaW5nCjIuIFBvcHVsYXRpb24gaW4gaW5zdGl0dXRpb25zCjMuIFBvcHVsYXRpb24gaW4gc2hpcHBpbmcKCihQb3B1bGF0aW9uIGluIHNoaXBwaW5nIGlzIGVzdGltYXRlZCBmcm9tIHRoZSAxOTUxIGNlbnN1cywgc28gaXMgdGhlIHNhbWUgZm9yIG1vc3QgeWVhcnMpCgojIyMjIDMuMSBPdmVyYWxsIHBvcHVsYXRpb24KCkZpcnN0LCBwbG90IHRoZSB0b3RhbCBwb3B1bGF0aW9uCgpgYGB7cn0KCm92ZXJhbGxfcG9wcyAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIpLCBhbHBoYT0wLjUsIGNvbG91ciA9ICJtZWRpdW1zZWFncmVlbiIsIGZpbGw9Im1lZGl1bXNlYWdyZWVuIikgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiksIGNvbG91ciA9ICJtZWRpdW1zZWFncmVlbiIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogdG90YWwgcG9wdWxhdGlvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMiLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkKCgpgYGAKCk5vdyB0aGUgcG9wdWxhdGlvbiBleGNsdWRpbmcgaW5zdGl0dXRpb25hbGlzZWQgYW5kIHNoaXBwaW5nIHBvcHVsYXRpb24KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgeD15ZWFyMiksIGFscGhhPTAuNSwgY29sb3VyID0gInB1cnBsZSIsIGZpbGw9InB1cnBsZSIpICsKICBnZW9tX3BvaW50KGFlcyh5PXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHg9eWVhcjIpLCBjb2xvdXIgPSAicHVycGxlIikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBwb3B1bGF0aW9uIGV4Y2x1ZGluZyBpbnN0aXR1dGlvbmFsaXNlZCBhbmQgc2hpcHBpbmciLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpCgoKYGBgCgojIyMjIDMuMiBQb3B1bGF0aW9uIGJ5IFdhcmQKClRoZXJlIGFyZSA1IERpdmlzaW9ucyBjb250YWluaW5nIDM3IFdhcmRzIGluIHRoZSBHbGFzZ293IENvcnBvcmF0aW9uLCB3aXRoIGNvbnNpc3RlbnQgYm91bmRhcmllcyBvdmVyIHRpbWUuCgpgYGB7cn0KI2xvb2stdXAgdGFibGUgZm9yIGRpdmlzaW9ucyBhbmQgd2FyZHMKd2FyZF9sb29rdXAgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAiZGl2aXNpb25zX3dhcmRzIikKCgp3YXJkX3BvcHMgPC0gcmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4Iiwgc2hlZXQgPSAid2FyZF9wb3B1bGF0aW9uIikKCndhcmRfcG9wcyAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludAp3YXJkX3BvcHMgPC0gd2FyZF9wb3BzICU+JQogIG11dGF0ZSh5ZWFyMiA9IHllYXIrMC41KQoKI0dldCB0aGUgRGl2aXNpb24gcG9wdWxhdGlvbgpkaXZpc2lvbl9wb3BzIDwtIHdhcmRfcG9wcyAlPiUKICBncm91cF9ieShkaXZpc2lvbiwgeWVhcikgJT4lCiAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgaW5zdGl0dXRpb25zID0gc3VtKGluc3RpdHV0aW9ucywgbmEucm0gPSBUUlVFKSwKICAgICAgICAgICAgc2hpcHBpbmcgPSBzdW0oc2hpcHBpbmcsIG5hLnJtID0gVFJVRSksCiAgICAgICAgICAgIHRvdGFsX3BvcHVsYXRpb24gPSBzdW0odG90YWxfcG9wdWxhdGlvbiwgbmEucm0gPSBUUlVFKSkKCmRpdmlzaW9uX3BvcHMgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpQbG90IHRoZSBvdmVyYWxsIHBvcHVsYXRpb24gYnkgRGl2aXNpb24gYW5kIFdhcmQKCmBgYHtyfQoKZGl2aXNpb25fcG9wcyAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT10b3RhbF9wb3B1bGF0aW9uLCB4PXllYXIyLCBjb2xvdXI9ZGl2aXNpb24sIGZpbGw9ZGl2aXNpb24pLCBhbHBoYT0wLjgpICsKICBnZW9tX3BvaW50KGFlcyh5PXRvdGFsX3BvcHVsYXRpb24sIHg9eWVhcjIsIGNvbG91cj1kaXZpc2lvbikpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAoZGl2aXNpb25+LikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiIikgKwogIHNjYWxlX2NvbG91cl9icmV3ZXIocGFsZXR0ZSA9ICJTZXQzIiwgbmFtZSA9ICIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IHRvdGFsIHBvcHVsYXRpb24gYnkgRGl2aXNpb24iLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIlBvcHVsYXRpb24iLAogICAgY2FwdGlvbiA9ICJNaWQteWVhciBlc3RpbWF0ZXNcbk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgpgYGAKCmBgYHtyfQoKd2FyZF9wb3BzICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uLCBmaWxsPWRpdmlzaW9uKSkgKwogIGdlb21fcG9pbnQoYWVzKHk9dG90YWxfcG9wdWxhdGlvbiwgeD15ZWFyMiwgY29sb3VyPWRpdmlzaW9uKSwgY29sb3VyPSJibGFjayIpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIGZhY2V0X3dyYXAod2FyZH4uLCBuY29sPTYpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDMiLCBuYW1lPSJEaXZpc2lvbiIpICsKICBzY2FsZV9jb2xvdXJfYnJld2VyKHBhbGV0dGUgPSAiU2V0MyIsIG5hbWUgPSAiRGl2aXNpb24iKSArCiAgbGFicygKICAgIHggPSAiIiwKICAgIHkgPSAiUG9wdWxhdGlvbiIsCiAgICBjYXB0aW9uID0gIk1pZC15ZWFyIGVzdGltYXRlc1xuTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczIucG5nIiksIGhlaWdodD0xNCwgd2lkdGg9MTIpCgpgYGAKCkFwcHJveGltYXRlbHksIGhvdyBtYW55IHBlcnNvbi15ZWFycyBvZiBmb2xsb3ctdXAgZG8gd2UgaGF2ZT8KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JQogIHVuZ3JvdXAoKSAlPiUKICBzdW1tYXJpc2UoYWNyb3NzKHllYXIsIGxlbmd0aCwgLm5hbWVzID0gInllYXJzIiksCiAgICAgICAgICAgIGFjcm9zcyhjKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pLCBzdW0pKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLmRvdWJsZSksIGNvbW1hKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCkNoYW5nZSBpbiBwb3B1bGF0aW9uIGJ5IHdhcmQKCmBgYHtyfQoKd2FyZF9wb3BzICU+JQogIGdyb3VwX2J5KHdhcmQpICU+JQogIHN1bW1hcmlzZShwY3RfY2hhbmdlX3BvcCA9IChsYXN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApIC0gZmlyc3QocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkpL2ZpcnN0KHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSAlPiUKICBtdXRhdGUocGN0X2NoYW5nZV9wb3AgPSBwZXJjZW50KHBjdF9jaGFuZ2VfcG9wKSkgJT4lCiAgYXJyYW5nZShwY3RfY2hhbmdlX3BvcCkgJT4lCiAgZGF0YXRhYmxlKCkKICAKCgpgYGAKCk91dHB1dCBwb3B1bGF0aW9uIGRlbnNpdHkgYnkgd2FyZCBhbmQgZGl2aXNvbiBmb3IgcmVncmVzc2lvbiBtb2RlbGxpbmcKCldhcmRzIGZpcnN0Cgooc3RvcHBlZCB3b3JraW5nLCBuZWVkIHRvIGZpeCkKCmBgYHtyfQoKIyB3YXJkX2NvdmFyaWF0ZXMgPC0gIGdsYXNnb3dfd2FyZHNfMTk1MSAlPiUKIyAgIGxlZnRfam9pbih3YXJkX3BvcHMpICU+JQojICAgbXV0YXRlKHBlb3BsZV9wZXJfa21fc3EgPSBhcy5kb3VibGUocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcC9hcmVhX2ttKSkKIyAKIyAjcGxvdCBpdCBvdXQKIyAKIyB3YXJkX2NvdmFyaWF0ZXMgJT4lCiMgICBnZ3Bsb3QoKSArCiMgICBnZW9tX3NmKGFlcyhmaWxsPXBlb3BsZV9wZXJfa21fc3EpKSArIAojICAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2w9NykgKwojICAgc2NhbGVfZmlsbF92aXJpZGlzX2Mob3B0aW9uPSJBIikgKwojICAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiMgICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdD0xKSkKIyAKIyBnZ3NhdmUoaGVyZSgiZmlndXJlcy93YXJkX3BvcF9kZW5zaXR5LnBuZyIpLCB3aWR0aD0xMCkKIyAKIyB3cml0ZV9yZHMod2FyZF9jb3ZhcmlhdGVzLCBoZXJlKCJwb3B1bGF0aW9ucy93YXJkX2NvdmFyaWF0ZXMucmRzIikpCgoKYGBgCgpOb3cgZGl2aXNpb25zIGZpcnN0CgoKKHN0b3BwZWQgd29ya2luZywgbmVlZCB0byBmaXgpCgpgYGB7cn0KCiMgZGl2aXNpb25fY292YXJpYXRlcyA8LSAgZ2xhc2dvd19kaXZpc2lvbnNfMTk1MSAlPiUKIyAgIGxlZnRfam9pbihkaXZpc2lvbl9wb3BzKSAlPiUKIyAgIG11dGF0ZShwZW9wbGVfcGVyX2ttX3NxID0gYXMuZG91YmxlKHRvdGFsX3BvcHVsYXRpb24vYXJlYV9rbSkpCiMgCiMgI3Bsb3QgaXQgb3V0CiMgCiMgZGl2aXNpb25fY292YXJpYXRlcyAlPiUKIyAgIGdncGxvdCgpICsKIyAgIGdlb21fc2YoYWVzKGZpbGw9cGVvcGxlX3Blcl9rbV9zcSkpICsgCiMgICBnZW9tX3NmX2xhYmVsKGFlcyhsYWJlbCA9IGRpdmlzaW9uKSwgc2l6ZT0zLCBmaWxsPU5BLCBsYWJlbC5zaXplID0gTkEsIGNvbG91cj0iYmxhY2siLCBmYW1pbHkgPSAiU2Vnb2UgVUkiKSArCiMgICBmYWNldF93cmFwKHllYXJ+LiwgbmNvbD03KSArCiMgICBzY2FsZV9maWxsX3ZpcmlkaXNfYyhvcHRpb249IkciKSArCiMgICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKIyAgICAgICAgIGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0PTEpKQojIAojIGdnc2F2ZShoZXJlKCJmaWd1cmVzL2RpdmlzaW9uX3BvcF9kZW5zaXR5LnBuZyIpLCB3aWR0aD0xMCkKIyAKIyB3cml0ZV9yZHMoZGl2aXNpb25fY292YXJpYXRlcywgaGVyZSgicG9wdWxhdGlvbnMvZGl2aXNpb25fY292YXJpYXRlcy5yZHMiKSkKCmBgYAoKCiMjIyMgMy4zIFBvcHVsYXRpb24gYnkgYWdlIGFuZCBzZXgKCmBgYHtyfQoKYWdlX3NleCA8LSByZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLCBzaGVldCA9ICJhZ2Vfc2V4X3BvcHVsYXRpb24iKSAlPiUKICBwaXZvdF9sb25nZXIoY29scyA9IGMobWFsZSwgZmVtYWxlKSwKICAgICAgICAgICAgICAgbmFtZXNfdG8gPSAic2V4IikKCiNjb2xsYXBzZSBkb3duIHRvIHNtYWxsZXIgYWdlIGdyb3VwcyB0byBiZSBtYW5hZ2VhYmxlCmFnZV9zZXggPC0gYWdlX3NleCAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2UgPT0gIjAgdG8gNCIgfiAiMDAgdG8gMDQiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlID09ICI1IHRvIDkiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTAgdG8gMTQiIH4gIjA1IHRvIDE0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMTUgdG8gMTkiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjAgdG8gMjQiIH4gIjE1IHRvIDI0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMjUgdG8gMjkiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzAgdG8gMzQiIH4gIjI1IHRvIDM0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiMzUgdG8gMzkiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDAgdG8gNDQiIH4gIjM1IHRvIDQ0IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNDUgdG8gNDkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTAgdG8gNTQiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZSA9PSAiNTUgdG8gNTkiIH4gIjQ1IHRvIDU5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIFRSVUUgfiAiNjAgJiB1cCIpKSAlPiUKICBncm91cF9ieSh5ZWFyLCBhZ2UsIHNleCkgJT4lCiAgbXV0YXRlKHZhbHVlID0gc3VtKHZhbHVlKSkgJT4lCiAgdW5ncm91cCgpCgoKCm1fYWdlX3NleCA8LSBsbSh2YWx1ZSB+IHNwbGluZXM6Om5zKHllYXIsIGtub3RzID0gMykqYWdlKnNleCwgZGF0YSA9IGFnZV9zZXgpCgpzdW1tYXJ5KG1fYWdlX3NleCkKCmFnZV9sZXZlbHMgPC0gYWdlX3NleCAlPiUgc2VsZWN0KGFnZSkgJT4lIGRpc3RpbmN0KCkgJT4lIHB1bGwoKSAKCmFnZV9zZXhfbmQgPC0gCiAgY3Jvc3NpbmcoCiAgICBhZ2U9YWdlX2xldmVscywKICAgIHNleD1jKCJtYWxlIiwgImZlbWFsZSIpLAogICAgeWVhciA9IDE5NTA6MTk2MwogICkKCnByZWRfcG9wcyA8LSBhZ2Vfc2V4X25kICU+JSBtb2RlbHI6OmFkZF9wcmVkaWN0aW9ucyhtX2FnZV9zZXgpCgpwcmVkX3BvcHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHJlZCwgY29sb3VyPWFnZSkpICsKICBnZW9tX2xpbmUoKSArCiAgZ2VvbV9wb2ludCgpICsKICBmYWNldF9ncmlkKHNleH4uKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscyA9IGNvbW1hLCBsaW1pdHMgPSBjKDAsIDEyNTAwMCkpCgojSG93IHdlbGwgZG8gdGhleSBtYXRjaCB1cCB3aXRoIG91ciBvdmVyYWxsIHBvcHVsYXRpb25zPwpwcmVkX3BvcHMgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgc3VtbWFyaXNlKHN1bV9wcmVkX3BvcCA9IHN1bShwcmVkKSkgJT4lCiAgcmlnaHRfam9pbihvdmVyYWxsX3BvcHMpICU+JQogIHNlbGVjdCh5ZWFyLCBzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhzdW1fcHJlZF9wb3AsIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHRvdGFsX3BvcHVsYXRpb24pKSAlPiUKICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT12YWx1ZSwgY29sb3VyPW5hbWUpKSArCiAgZ2VvbV9wb2ludCgpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzID0gY29tbWEsIGxpbWl0cyA9IGMoODAwMDAwLCAxMjUwMDAwKSkKCnByZWRfcG9wcyAlPiUKICBncm91cF9ieSh5ZWFyLCBzZXgpICU+JQogIHN1bW1hcmlzZShzdW0gPSBzdW0ocHJlZCkpICU+JQogIGdyb3VwX2J5KHllYXIpICU+JQogIG11dGF0ZShzZXhfcmF0aW8gPSBmaXJzdChzdW0pL2xhc3Qoc3VtKSkKYGBgCgoKCgoKUG9wdWxhdGlvbiBweXJhbWlkcwoKYGBge3J9CgpsYWJlbF9hYnMgPC0gZnVuY3Rpb24oeCkgewogIGNvbW1hKGFicyh4KSkKfQoKCnByZWRfcG9wcyAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoeWVhcikgJT4lCiAgbXV0YXRlKHllYXJfcG9wID0gc3VtKHByZWQpLAogICAgICAgICBhZ2Vfc2V4X3BjdCA9IHBlcmNlbnQocHJlZC95ZWFyX3BvcCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJtYWxlIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ImZlbWFsZSIgfiAiRmVtYWxlIikpICU+JQogIGdncGxvdCgKICAgIGFlcyh4ID0gYWdlLCBmaWxsID0gc2V4LCAKICAgICAgICB5ID0gaWZlbHNlKHRlc3QgPSBzZXggPT0gIkZlbWFsZSIseWVzID0gLXByZWQsIG5vID0gcHJlZCkpKSArIAogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgZ2VvbV90ZXh0KGFlcyhsYWJlbCA9IGFnZV9zZXhfcGN0KSwKICAgICAgICAgICAgcG9zaXRpb249IHBvc2l0aW9uX3N0YWNrKHZqdXN0PTAuNSksIGNvbG91cj0iYmxhY2siLCBzaXplPTIuNSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sPTcpICsKICBjb29yZF9mbGlwKCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBsYWJlbF9hYnMpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjQ0Q3QUM1IiwgImNhZGV0Ymx1ZTMiKSwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT05MCwgaGp1c3QgPSAxLCB2anVzdD0wLjUpLAogICAgICAgIGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IiIsIHk9IiIpIAoKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MzLnBuZyIpLCB3aWR0aD0xMCkKCgpgYGAKCk5vdCBwZXJmZWN0LCBidXQgcmVzb25hYmx5IGdvb2QuIEJ1dCBhaGhoaGguLi4gdGhlIGFnZSBncm91cHMgZG9uJ3QgYWxpZ24gd2l0aCB0aGUgY2FzZSBub3RpZmljYXRpb24gYWdlIGdyb3VwcyEgQ29tZSBiYWNrIHRvIHRoaW5rIGFib3V0IHRoaXMgbGF0ZXIuCgoKIyMjIDQuIFR1YmVyY3Vsb3NpcyBjYXNlcwoKSW1wb3J0IHRoZSB0dWJlcmN1bG9zaXMgY2FzZXMgZGF0YXNldAoKCiMjIyMgNC4xIE92ZXJhbGwgbm90aWZpY2F0aW9ucwoKT3ZlcmFsbCwgYnkgeWVhci4KCmBgYHtyfQoKY2FzZXNfYnlfeWVhciA8LSByZWFkX3hsc3goIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsIHNoZWV0ID0gImJ5X3llYXIiKQoKY2FzZXNfYnlfeWVhciU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV95ZWFyIDwtIGNhc2VzX2J5X3llYXIgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpCgpgYGAKClBsb3QgdGhlIG92ZXJhbGwgbnVtYmVyIG9mIGNhc2Ugbm90aWZpZWQgcGVyIHllYXIsIGJ5IHB1bG1vbmFyeSBhbmQgZXh0cmEgcHVsbW9uYXJ5IGNsYXNzaWZpY2F0aW9uLgoKYGBge3J9CgpjYXNlc19ieV95ZWFyICU+JQogIHNlbGVjdCgtdG90YWxfbm90aWZpY2F0aW9ucywgLXllYXIpICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhwdWxtb25hcnlfbm90aWZpY2F0aW9ucywgYG5vbi1wdWxtb25hcnlfbm90aWZpY2F0aW9uc2ApKSAlPiUKICBtdXRhdGUobmFtZSA9IGNhc2Vfd2hlbihuYW1lID09ICJwdWxtb25hcnlfbm90aWZpY2F0aW9ucyIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PXZhbHVlLCB4PXllYXIyLCBncm91cCA9IG5hbWUsIGZpbGw9bmFtZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscykgKwogIHNjYWxlX2ZpbGxfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIsIG5hbWU9IiIpICsKICBsYWJzKAogICAgdGl0bGUgPSAiR2xhc2dvdyBDb3Jwb3JhdGlvbjogVHViZXJjdWxvc2lzIG5vdGlmaWNhdGlvbnMiLAogICAgc3VidGl0bGUgPSAiMTk1MCB0byAxOTYzLCBieSBUQiBkaXNlYXNlIGNsYXNzaWZpY2F0aW9uIiwKICAgIHggPSAiWWVhciIsCiAgICB5ID0gIk51bWJlciBvZiBjYXNlcyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKICAKCmBgYAoKIyMjIyA0LjIgTm90aWZpY2F0aW9ucyBieSBEaXZpc2lvbgoKUmVhZCBpbiB0aGUgZGF0YXNldHMgYW5kIG1lcmdlIHRvZ2V0aGVyLgoKYGBge3J9CgojbGlzdCBhbGwgdGhlIHNoZWV0cwphbGxfc2hlZXRzIDwtIGV4Y2VsX3NoZWV0cygiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IikKCiNnZXQgdGhlIHdhcmQgc2hlZXRzCndhcmRfc2hlZXRzIDwtIGVuZnJhbWUoYWxsX3NoZWV0cykgJT4lCiAgZmlsdGVyKGdyZXBsKCJieV93YXJkIiwgdmFsdWUpKSAlPiUKICBwdWxsKHZhbHVlKQoKCmNhc2VzX2J5X3dhcmRfc2V4X3llYXIgPC0gbWFwX2RmKHdhcmRfc2hlZXRzLCB+cmVhZF94bHN4KHBhdGggPSAiMjAyMy0xMS0yOF9nbGFzZ293LWFjZi54bHN4IiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzaGVldCA9IC4pKQoKY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCkFnZ3JlZ2F0ZSB0b2dldGhlciB0byBnZXQgY2FzZXMgYnkgZGl2aXNpb24KCmBgYHtyfQoKY2FzZXNfYnlfZGl2aXNpb24gPC0gY2FzZXNfYnlfd2FyZF9zZXhfeWVhciAlPiUKICBsZWZ0X2pvaW4od2FyZF9sb29rdXApICU+JQogIGdyb3VwX2J5KGRpdmlzaW9uLCB5ZWFyLCB0Yl90eXBlKSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMsIG5hLnJtID0gVFJVRSkpCgojc2hpZnQgeWVhciB0byBtaWRwb2ludApjYXNlc19ieV9kaXZpc2lvbiA8LSBjYXNlc19ieV9kaXZpc2lvbiAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV9kaXZpc2lvbiAgJT4lCiAgc2VsZWN0KC15ZWFyMikgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyh3aGVyZShpcy5udW1lcmljKSAmICEoeWVhciksICB+Y29tbWEoLikpKSAlPiUKICBkYXRhdGFibGUoKQoKCmNhc2VzX2J5X2RpdmlzaW9uICU+JQogIG11dGF0ZSh0Yl90eXBlID0gY2FzZV93aGVuKHRiX3R5cGUgPT0gIlB1bG1vbmFyeSIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICB0Yl90eXBlID09ICJOb24tUHVsbW9uYXJ5IiB+ICJFeHRyYS1wdWxtb25hcnkgVEIiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fYXJlYShhZXMoeT1jYXNlcywgeD15ZWFyMiwgZ3JvdXAgPSB0Yl90eXBlLCBmaWxsPXRiX3R5cGUpLCBhbHBoYT0wLjUpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9zdGFydCksIGxpbmV0eXBlPTMpICsKICBnZW9tX3ZsaW5lKGFlcyh4aW50ZXJjZXB0PWFjZl9lbmQpLCBsaW5ldHlwZT0zKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxhYmVscz1jb21tYSkgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHMgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkgKwogIGZhY2V0X3dyYXAoZGl2aXNpb25+Liwgc2NhbGVzID0gImZyZWVfeSIpICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBub3RpZmljYXRpb25zIGJ5IERpdmlzaW9uIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpgYGAKCiMjIyMgNC4zIE5vdGlmaWNhdGlvbnMgYnkgd2FyZAoKYGBge3J9CgoKY2FzZXNfYnlfd2FyZCA8LSBjYXNlc19ieV93YXJkX3NleF95ZWFyICU+JQogIGdyb3VwX2J5KHdhcmQsIHllYXIsIHRiX3R5cGUpICU+JQogIHN1bW1hcmlzZShjYXNlcyA9IHN1bShjYXNlcywgbmEucm0gPSBUUlVFKSkgJT4lCiAgdW5ncm91cCgpCgpjYXNlc19ieV93YXJkICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgc2VsZWN0KHllYXIsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiNzaGlmdCB5ZWFyIHRvIG1pZHBvaW50CmNhc2VzX2J5X3dhcmQgPC0gY2FzZXNfYnlfd2FyZCAlPiUKICBtdXRhdGUoeWVhcjIgPSB5ZWFyKzAuNSkKCmNhc2VzX2J5X3dhcmQgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWNhc2VzLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuOCkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4sIHNjYWxlcyA9ICJmcmVlX3kiKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgbm90aWZpY2F0aW9ucyBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJOdW1iZXIgb2YgY2FzZXMiLAogICAgY2FwdGlvbiA9ICJNYXNzIG1pbmlhdHVyZSBYLXJheSBjYW1wYWlnbiBwZXJpb2QgYmV0d2VlbiBkYXNoZWQgbGluZXMgKDExdGggTWFyY2gtMTJ0aCBBcHJpbCAxOTU3KVxuTm90ZTogZXh0cmEtcHVsbW9uYXJ5IFRCIGNhc2VzIGJ5IERpdmlzaW9uL1dhcmQgbm90IHJlcG9ydGVkIGluIDE5NjItMTk2MyIKICApICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCgpgYGAKCiMjIyMgNC40IE5vdGlmaWNhdGlvbnMgYnkgYWdlIGFuZCBzZXgKCkFzIHdlIGRvbid0IGhhdmUgZGVub21pbmF0b3JzLCB3ZSB3aWxsIGp1c3QgbW9kZWwgdGhlIGNoYW5nZSBpbiBjb3VudHMuCgpgYGB7cn0KCiNsaXN0IGFsbCB0aGUgc2hlZXRzCmFsbF9zaGVldHMgPC0gZXhjZWxfc2hlZXRzKCIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giKQoKI2dldCB0aGUgd2FyZCBzaGVldHMKYWdlX3NleF9zaGVldHMgPC0gZW5mcmFtZShhbGxfc2hlZXRzKSAlPiUKICBmaWx0ZXIoZ3JlcGwoImJ5X2FnZV9zZXgiLCB2YWx1ZSkpICU+JQogIHB1bGwodmFsdWUpCgoKY2FzZXNfYnlfYWdlX3NleCA8LSBtYXBfZGYoYWdlX3NleF9zaGVldHMsIH5yZWFkX3hsc3gocGF0aCA9ICIyMDIzLTExLTI4X2dsYXNnb3ctYWNmLnhsc3giLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNoZWV0ID0gLikpCgpjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCiMjIyA0LjUgVXB0YWtlIG9mIHNjcmVlbmluZwoKV2hhdCBwZXJjZW50YWdlIG9mIGFkdWx0cyAoMTUrIHBhcnRpY2lwYXRlZCBpbiB0aGUgaW50ZXJ2ZW50aW9uIGluIDE5NTcpPwoKYGBge3J9CiMgCiMgcHJlZF9wb3BzICU+JQojICAgdW5ncm91cCgpICU+JQojICAgZmlsdGVyKHllYXI9PTE5NTcpICU+JQojICAgZmlsdGVyKGFnZSAhPSAiMDAgdG8gMDQiLAojICAgICAgICAgIGFnZSAhPSAiMDUgdG8gMTQiKSAlPiUKIyAgIHN1bW1hcmlzZSh0b3RhbF9wb3AgPSBzdW0ocHJlZCkpICU+JQojICAgbXV0YXRlKGN4cl9zY3JlZW5lZCA9IDYyMjM0OSkgJT4lCiMgICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQojIAojIHByZWRfcG9wcyAlPiUKIyAgIHVuZ3JvdXAoKSAlPiUKIyAgIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKIyAgIGZpbHRlcihhZ2UgIT0gIjAwIHRvIDA0IiwKIyAgICAgICAgICBhZ2UgIT0gIjA1IHRvIDE0IikgJT4lCiMgICBzdW1tYXJpc2UodG90YWxfcG9wID0gc3VtKHByZWQpLCAuYnk9c2V4KSAlPiUKIyAgIG11dGF0ZShjeHJfc2NyZWVuZWQgPSBjKDM0MDQ3NCwgMjgxODc1KSkgJT4lCiMgICBtdXRhdGUocGN0X3BvcF9jeHJfc2NyZWVuZWQgPSBwZXJjZW50KGN4cl9zY3JlZW5lZC90b3RhbF9wb3ApKQoKCmBgYAoKTm90ZSB0aGF0IGluIHRoZSBSZXBvcnQgb2YgU2lyIEtlbm5ldGggQ293YW4sIHdlIGhhdmUgdGhlIGZvbGxvd2luZyBlc3RpbWF0ZXMgb2YgcGFydGljaXBhdGlvbiAod2Ugd2lsbCB1c2UgdGhlc2UgZm9yIHRoZSBtYW51c2NyaXB0LCBhcyB0aGV5IGFyZSBub3QgYmFzZWQgb24gbXkgZXN0aW1hdGVzKQoKYGBge3J9Cm1hbGVfYWR1bHRfcmVzaWRlbnRfcGFydGljaXBhdGlvbiA8LSAyODE4NzUKZmVtYWxlX2FkdWx0X3Jlc2lkZW50X3BhcnRpY2lwYXRpb24gPC0gMzQwNDc0Cm1hbGVfYWR1bHRfcmVzaWRlbnRfcG9wdWxhdGlvbiA8LSAzODE3MTMKZmVtYWxlX2FkdWx0X3Jlc2lkZW50X3BvcHVsYXRpb24gPC0gNDM3NTg4Cgojb3ZlcmFsbCBwYXJ0aWNpcGF0aW9uCihtYWxlX2FkdWx0X3Jlc2lkZW50X3BhcnRpY2lwYXRpb24rZmVtYWxlX2FkdWx0X3Jlc2lkZW50X3BhcnRpY2lwYXRpb24pLyhtYWxlX2FkdWx0X3Jlc2lkZW50X3BvcHVsYXRpb24rZmVtYWxlX2FkdWx0X3Jlc2lkZW50X3BvcHVsYXRpb24pCgojbWFsZSBwYXJ0aWNpcGF0aW9uCm1hbGVfYWR1bHRfcmVzaWRlbnRfcGFydGljaXBhdGlvbi9tYWxlX2FkdWx0X3Jlc2lkZW50X3BvcHVsYXRpb24KCiNmZW1hbGUgcGFydGljaXBhdGlvbgpmZW1hbGVfYWR1bHRfcmVzaWRlbnRfcGFydGljaXBhdGlvbi9mZW1hbGVfYWR1bHRfcmVzaWRlbnRfcG9wdWxhdGlvbgoKCmBgYAoKCkxvb2sgYXQgdXB0YWtlIG9mIHNjcmVlbmluZyBieSBhZ2UgYW5kIHNleAoKYGBge3J9CgoKdXB0YWtlX2FnZV9zZXggPC0gcmVhZF94bHN4KCIyMDI0LTAzLTI2X21hc3NfeHJheV91cHRha2UueGxzeCIsIHNoZWV0ID0gInVwdGFrZV9hZ2Vfc2V4IikKCnVwdGFrZV9hZ2Vfc2V4ICU+JQogIG11dGF0ZSh1cHRha2UgPSBleGFtaW5lZC9yZXNpZGVudF9wb3B1bGF0aW9uKSAlPiUKICBtdXRhdGUoZXhhbWluZWRfbCA9IGNvbW1hKGV4YW1pbmVkKSwKICAgICAgICAgcmVzaWRlbnRfcG9wdWxhdGlvbl9sID0gY29tbWEocmVzaWRlbnRfcG9wdWxhdGlvbiksCiAgICAgICAgIHVwdGFrZV9sID0gcGVyY2VudCh1cHRha2UsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShsYWJlbCA9IGdsdWUoIntleGFtaW5lZF9sfS97cmVzaWRlbnRfcG9wdWxhdGlvbl9sfSAoe3VwdGFrZV9sfSkiKSkgJT4lCiAgZmlsdGVyKGFnZSAhPSIwMC0xNCIpICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0ibSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJmIiB+ICJGZW1hbGUiKSkgJT4lCiAgZ2dwbG90KGFlcyh4PWFnZSwgeT11cHRha2UsIGdyb3VwPXNleCwgZmlsbD1zZXgpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIsIHBvc2l0aW9uID0gImRvZGdlIikgKwogIGdlb21fdGV4dChhZXMobGFiZWw9dXB0YWtlX2wpLCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoPTAuODUpLHZqdXN0PTIpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPXBlcmNlbnQpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjQ0Q3QUM1IiwgImNhZGV0Ymx1ZTMiKSwgbmFtZT0iIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSIiLCB5PSIiKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvczQucG5nIikpCgpgYGAKClVwdGFrZSBieSBkaXZpc2lvbgoKYGBge3J9Cgp1cHRha2VfZGl2aXNpb24gPC0gcmVhZF94bHN4KCIyMDI0LTAzLTI2X21hc3NfeHJheV91cHRha2UueGxzeCIsIHNoZWV0ID0gInVwdGFrZV9kaXZpc2lvbiIpCgpkaXZpc2lvbl9wb3BzICU+JQogIGZpbHRlcih5ZWFyPT0xOTU3KSAlPiUKICBzZWxlY3QoZGl2aXNpb24sIHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApICU+JQogIGxlZnRfam9pbih1cHRha2VfZGl2aXNpb24pICU+JQogIG11dGF0ZShwY3RfcG9wX2V4YW1pbmVkID0gZXhhbWluZWQvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkKCgpgYGAKCgoKCiMjIyA1IFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgojIyMjIDUuMSBPdmVyYWxsIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzCgpOb3cgY2FsY3VsYXRlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIHBlciAxMDAsMDAwIHBvcHVsYXRpb24KCk1lcmdlIHRoZSBub3RpZmljYXRpb24gYW5kIHBvcHVsYXRpb24gZGVub21pbmF0b3IgZGF0YXNldHMgdG9nZXRoZXIuCgpIZXJlIHdlIG5lZWQgdG8gaW5jbHVkZSB0aGUgd2hvbGUgcG9wdWxhdGlvbiAod2l0aCBzaGlwcGluZyBhbmQgaW5zdGl0dXRpb25zKSBhcyB0aGV5IGFyZSBpbmNsdWRlZCBpbiB0aGUgbm90aWZpY2F0aW9ucy4KCmBgYHtyfQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9wb3BzICU+JQogIGxlZnRfam9pbihjYXNlc19ieV95ZWFyKQoKb3ZlcmFsbF9pbmMgPC0gb3ZlcmFsbF9pbmMgJT4lCiAgbXV0YXRlKGluY19wdWxtXzEwMGsgPSBwdWxtb25hcnlfbm90aWZpY2F0aW9ucy90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jX2VwXzEwMGsgPSBgbm9uLXB1bG1vbmFyeV9ub3RpZmljYXRpb25zYC90b3RhbF9wb3B1bGF0aW9uKjEwMDAwMCwKICAgICAgICAgaW5jXzEwMGsgPSB0b3RhbF9ub3RpZmljYXRpb25zL3RvdGFsX3BvcHVsYXRpb24qMTAwMDAwKQoKb3ZlcmFsbF9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGluY18xMDBrLCBpbmNfcHVsbV8xMDBrLCBpbmNfZXBfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwaywgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgpgYGB7cn0KCm92ZXJhbGxfaW5jICU+JQogIHNlbGVjdCh5ZWFyMiwgaW5jX3B1bG1fMTAwaywgaW5jX2VwXzEwMGspICU+JQogIHBpdm90X2xvbmdlcihjb2xzID0gYyhpbmNfcHVsbV8xMDBrLCBgaW5jX2VwXzEwMGtgKSkgJT4lCiAgbXV0YXRlKG5hbWUgPSBjYXNlX3doZW4obmFtZSA9PSAiaW5jX3B1bG1fMTAwayIgfiAiUHVsbW9uYXJ5IFRCIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lID09ICJpbmNfZXBfMTAwayIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9dmFsdWUsIHg9eWVhcjIsIGdyb3VwID0gbmFtZSwgZmlsbD1uYW1lKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgc2NhbGVfZmlsbF9icmV3ZXIocGFsZXR0ZSA9ICJTZXQxIiwgbmFtZT0iIikgKwogIGxhYnMoCiAgICB0aXRsZSA9ICJHbGFzZ293IENvcnBvcmF0aW9uOiBUdWJlcmN1bG9zaXMgY2FzZSBub3RpZmljYXRpb24gcmF0ZSIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCkNoYW5nZSBpbiBjYXNlIG5vdGlmaWNhdGlvbiByYXRlcyBwcmUtaW50ZXJ2ZW50aW9uCgpgYGB7cn0KI3ByZS1BQ0YKb3ZlcmFsbF9pbmMgJT4lCiAgZmlsdGVyKHllYXIgJWluJSAxOTUwOjE5NTYpICU+JQogIHN1bW1hcmlzZShjaGFuZ2UgPSAoKChsYXN0KGluY19wdWxtXzEwMGspLWZpcnN0KGluY19wdWxtXzEwMGspKS9maXJzdChpbmNfcHVsbV8xMDBrKSkvNykqMTAwKQoKI3Bvc3QtQUNGCm92ZXJhbGxfaW5jICU+JQogIGZpbHRlcih5ZWFyICVpbiUgMTk1ODoxOTYzKSAlPiUKICBzdW1tYXJpc2UoY2hhbmdlID0gKCgobGFzdChpbmNfcHVsbV8xMDBrKS1maXJzdChpbmNfcHVsbV8xMDBrKSkvZmlyc3QoaW5jX3B1bG1fMTAwaykpLzYpKjEwMCkKCmBgYAoKCgoKIyMjIyA1LjIgVEIgY2FzZSBub3RpZmljYXRpb24gcmF0ZXMgYnkgRGl2aXNpb24KCmBgYHtyfQoKZGl2aXNpb25faW5jIDwtIGRpdmlzaW9uX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X2RpdmlzaW9uKQoKCmRpdmlzaW9uX2luYyA8LSBkaXZpc2lvbl9pbmMgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gY2FzZXMvdG90YWxfcG9wdWxhdGlvbioxMDAwMDApCgpkaXZpc2lvbl9pbmMgJT4lCiAgc2VsZWN0KHllYXIsIGRpdmlzaW9uLCB0Yl90eXBlLCBpbmNfMTAwaykgJT4lCiAgbXV0YXRlX2F0KC52YXJzID0gdmFycyhpbmNfMTAwayksCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhyb3VuZCkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmRpdmlzaW9uX2luYyAlPiUKICBtdXRhdGUodGJfdHlwZSA9IGNhc2Vfd2hlbih0Yl90eXBlID09ICJQdWxtb25hcnkiIH4gIlB1bG1vbmFyeSBUQiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgdGJfdHlwZSA9PSAiTm9uLVB1bG1vbmFyeSIgfiAiRXh0cmEtcHVsbW9uYXJ5IFRCIikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2FyZWEoYWVzKHk9aW5jXzEwMGssIHg9eWVhcjIsIGdyb3VwID0gdGJfdHlwZSwgZmlsbD10Yl90eXBlKSwgYWxwaGE9MC41KSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBmYWNldF93cmFwKGRpdmlzaW9ufi4pICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlLCBieSBEaXZpc2lvbiIsCiAgICBzdWJ0aXRsZSA9ICIxOTUwIHRvIDE5NjMsIGJ5IFRCIGRpc2Vhc2UgY2xhc3NpZmljYXRpb24iLAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1Nylcbk5vdGU6IGV4dHJhLXB1bG1vbmFyeSBUQiBjYXNlcyBieSBEaXZpc2lvbi9XYXJkIG5vdCByZXBvcnRlZCBpbiAxOTYyLTE5NjMiCiAgKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgpgYGAKCiMjIyMgNS4yIFRCIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGVzIGJ5IFdhcmQKCkhlcmUgd2Ugd2lsbCBmaWx0ZXIgb3V0IHRoZSBpbnN0aXR1dGlvbnMgYW5kIGhhcmJvdXIgZnJvbSB0aGUgZGVub21pbmF0b3JzLCBhcyB3ZSBkb24ndCBoYXZlIHJlbGlhYmxlIHBvcHVsYXRpb24gZGVub21pbmF0b3JzIGZvciB0aGVtLgoKYGBge3J9Cgp3YXJkX2luYyA8LSB3YXJkX3BvcHMgJT4lCiAgbGVmdF9qb2luKGNhc2VzX2J5X3dhcmQpCgoKd2FyZF9pbmMgPC0gd2FyZF9pbmMgJT4lCiAgbXV0YXRlKGluY18xMDBrID0gY2FzZXMvcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCoxMDAwMDApCgp3YXJkX2luYyAlPiUKICBzZWxlY3QoeWVhciwgd2FyZCwgdGJfdHlwZSwgaW5jXzEwMGspICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoaW5jXzEwMGspLAogICAgICAgICAgICAuZnVucyA9IGZ1bnMocm91bmQpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKCmBgYHtyfQoKd2FyZF9pbmMgJT4lCiAgbXV0YXRlKHRiX3R5cGUgPSBjYXNlX3doZW4odGJfdHlwZSA9PSAiUHVsbW9uYXJ5IiB+ICJQdWxtb25hcnkgVEIiLAogICAgICAgICAgICAgICAgICAgICAgICAgIHRiX3R5cGUgPT0gIk5vbi1QdWxtb25hcnkiIH4gIkV4dHJhLXB1bG1vbmFyeSBUQiIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9hcmVhKGFlcyh5PWluY18xMDBrLCB4PXllYXIyLCBncm91cCA9IHRiX3R5cGUsIGZpbGw9dGJfdHlwZSksIGFscGhhPTAuNSkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX3N0YXJ0KSwgbGluZXR5cGU9MykgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBzY2FsZV95X2NvbnRpbnVvdXMobGFiZWxzPWNvbW1hKSArCiAgc2NhbGVfeF9jb250aW51b3VzKGxhYmVscyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBicmVha3MgPSB5ZWFyX2xhYmVscywKICAgICAgICAgICAgICAgICAgICAgZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgZmFjZXRfd3JhcCh3YXJkfi4pICsKICBzY2FsZV9maWxsX2JyZXdlcihwYWxldHRlID0gIlNldDEiLCBuYW1lPSIiKSArCiAgbGFicygKICAgIHRpdGxlID0gIkdsYXNnb3cgQ29ycG9yYXRpb246IFR1YmVyY3Vsb3NpcyBjYXNlIG5vdGlmaWNhdGlvbiByYXRlLCBieSBXYXJkIiwKICAgIHN1YnRpdGxlID0gIjE5NTAgdG8gMTk2MywgYnkgVEIgZGlzZWFzZSBjbGFzc2lmaWNhdGlvbiIsCiAgICB4ID0gIlllYXIiLAogICAgeSA9ICJJbmNpZGVuY2UgKHBlciAxMDAsMDAwKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYnkgRGl2aXNpb24vV2FyZCBub3QgcmVwb3J0ZWQgaW4gMTk2Mi0xOTYzIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKCgoKYGBgCgpPbiBhIG1hcAoKYGBge3IsIHdhcm5pbmc9RkFMU0V9CgpzdF9hc19zZihsZWZ0X2pvaW4od2FyZF9pbmMsIGdsYXNnb3dfd2FyZHNfMTk1MSkpICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9aW5jXzEwMGspKSArCiAgZmFjZXRfd3JhcCh5ZWFyfi4sIG5jb2wgPSA3KSArCiAgc2NhbGVfZmlsbF92aXJpZGlzX2MobmFtZT0iQ2FzZSBub3RpZmljYXRpb24gcmF0ZSAocGVyIDEwMCwwMDApIiwKICAgICAgICAgICAgICAgICAgICAgICBvcHRpb24gPSAiQSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgbGVnZW5kLmtleS53aWR0aCA9IHVuaXQoMiwgImNtIiksCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkgKwogIGd1aWRlcyhmaWxsPWd1aWRlX2NvbG9yYmFyKHRpdGxlLnBvc2l0aW9uID0gInRvcCIpKQoKCgpgYGAKCgojIyMgNi4gVEIgTW9ydGFsaXR5CgojIyMjIDYuMSBPdmVyYWxsIE1vcnRhbGl0eQoKSW1wb3J0IHRoZSBUQiBtb3J0YWxpdHkgZGF0YS4KCkZpcnN0LCBvdmVyYWxsIGRlYXRocy4gTm90ZSB0aGF0IGluIHRoZSBvcmlnaW5hbCByZXBvcnRzLCB3ZSBoYXZlIGEgcHVsbW9uYXJ5IFRCIGRlYXRoIHJhdGUgcGVyIG1pbGxpb24gZm9yIGFsbCB5ZWFycywgYW5kIG51bWJlcnMgb2YgcHVsbW9uYXJ5IFRCIGRlYXRocyBmb3IgZWFjaCB5ZWFyIGFwYXJ0IGZyb20gMTk1MC4KCmBgYHtyfQoKI2dldCB0aGUgb3ZlcmFsbCBtb3J0YWxpdHkgc2hlZXRzCmRlYXRoc19zaGVldHMgPC0gZW5mcmFtZShhbGxfc2hlZXRzKSAlPiUKICBmaWx0ZXIoZ3JlcGwoImRlYXRocyIsIHZhbHVlKSkgJT4lCiAgcHVsbCh2YWx1ZSkKCgpvdmVyYWxsX2RlYXRocyA8LSBtYXBfZGYoZGVhdGhzX3NoZWV0cywgfnJlYWRfeGxzeChwYXRoID0gIjIwMjMtMTEtMjhfZ2xhc2dvdy1hY2YueGxzeCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2hlZXQgPSAuKSkKCm92ZXJhbGxfZGVhdGhzICU+JQogIG11dGF0ZShhY3Jvc3Mod2hlcmUoaXMubnVtZXJpYykgJiAhKHllYXIpLCAgfmNvbW1hKC4pKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgoKYGBgCgpQbG90IHRoZSByYXcgbnVtYmVycyBvZiBwdWxtb25hcnkgZGVhdGhzCgpgYGB7cn0KCm92ZXJhbGxfZGVhdGhzICU+JQogIGdncGxvdChhZXMoeD15ZWFyLCB5PXB1bG1vbmFyeV9kZWF0aHMpKSArCiAgZ2VvbV9saW5lKGNvbG91ciA9ICIjREUwRDkyIikgKwogIGdlb21fcG9pbnQoY29sb3VyID0gIiNERTBEOTIiKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIGxhYnMoeT0iUHVsbW9uYXJ5IFRCIGRlYXRocyBwZXIgeWVhciIsCiAgICAgICB4ID0gIlllYXIiLAogICAgICAgdGl0bGUgPSAiTnVtYmVycyBvZiBwdWxtb25hcnkgVEIgZGVhdGhzIiwKICAgICAgIHN1YnRpdGxlID0gIkdsYXNnb3csIDE5NTAtMTk2MyIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpXG5Ob3RlOiBubyBkYXRhIGZvciAxOTUwIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCmBgYAoKTm93IHRoZSBpbmNpZGVuY2Ugb2YgcHVsbW9uYXJ5IFRCIGRlYXRoCgpgYGB7cn0Kb3ZlcmFsbF9kZWF0aHMgJT4lCiAgZ2dwbG90KGFlcyh4PXllYXIsIHk9cHVsbW9uYXJ5X2RlYXRoX3JhdGVfcGVyXzEwMGspKSArCiAgZ2VvbV9saW5lKGNvbG91ciA9ICIjNEQ2Q0ZBIikgKwogIGdlb21fcG9pbnQoY29sb3VyID0gIiM0RDZDRkEiKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2Zfc3RhcnQpLCBsaW5ldHlwZT0zKSArCiAgZ2VvbV92bGluZShhZXMoeGludGVyY2VwdD1hY2ZfZW5kKSwgbGluZXR5cGU9MykgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzKSArCiAgbGFicyh5PSJBbm51YWwgaW5jaWRlbmNlIG9mIGRlYXRoIChwZXIgMTAwLDAwMCkiLAogICAgICAgeCA9ICJZZWFyIiwKICAgIGNhcHRpb24gPSAiTWFzcyBtaW5pYXR1cmUgWC1yYXkgY2FtcGFpZ24gcGVyaW9kIGJldHdlZW4gZGFzaGVkIGxpbmVzICgxMXRoIE1hcmNoLTEydGggQXByaWwgMTk1NykiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zOC5wbmciKSwgd2lkdGg9MTApCgpgYGAKCgojIyMgNi4gVGFibGUgMQoKTWFrZSBUYWJsZSAxIGhlcmUsIGFuZCBzYXZlIGZvciBwdWJsaWNhdGlvbi4KCmBgYHtyfQoKb3ZlcmFsbF9wb3BzICU+JSAKICBzZWxlY3QoeWVhciwgdG90YWxfcG9wdWxhdGlvbikgJT4lCiAgbGVmdF9qb2luKG92ZXJhbGxfaW5jICU+JQogICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCAKICAgICAgICAgICAgICAgICAgICAgcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnMsIGluY19wdWxtXzEwMGssCiAgICAgICAgICAgICAgICAgICAgIGBub24tcHVsbW9uYXJ5X25vdGlmaWNhdGlvbnNgLCBpbmNfZXBfMTAwaywKICAgICAgICAgICAgICAgICAgICAgdG90YWxfbm90aWZpY2F0aW9ucywgaW5jXzEwMGspKSAlPiUKICBsZWZ0X2pvaW4ob3ZlcmFsbF9kZWF0aHMgJT4lCiAgICAgICAgICAgICAgc2VsZWN0KHllYXIsCiAgICAgICAgICAgICAgICAgICAgIHB1bG1vbmFyeV9kZWF0aHMsIHB1bG1vbmFyeV9kZWF0aF9yYXRlX3Blcl8xMDBrKSkgJT4lCiAgbXV0YXRlKHBlcmNlbnRfcHVsbW9uYXJ5ID0gcGVyY2VudChwdWxtb25hcnlfbm90aWZpY2F0aW9ucy8odG90YWxfbm90aWZpY2F0aW9ucyApLCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5yb3VuZCguLCBkaWdpdHM9MSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKHdoZXJlKGlzLm51bWVyaWMpICYgISh5ZWFyKSwgIH5jb21tYSguKSkpCgpgYGAKCkNvbXBhcmlzb24gZm8gYWdlLXNleCBkaXN0cmlidXRpb24gb2YgY2FzZXMgaW4gMTk1MC0xOTU2IHZzLiAxOTU3CgpgYGB7cn0KCmxhYmVsX2FiczIgPC0gZnVuY3Rpb24oeCkgewogIHBlcmNlbnQoYWJzKHgpKQp9CgoKCmNhc2VzX2J5X2FnZV9zZXggJT4lIAogIHVuZ3JvdXAoKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKHllYXIgJWluJSBjKDE5NTA6MTk1NikgfiAiYS4gcHJlLWFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1NykgfiAiYi4gYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU4OjE5NjMpIH4gImMuIHBvc3QtYWNmIikpICU+JQogIGdyb3VwX2J5KGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBzdW1tYXJpc2UoY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgZ3JvdXBfYnkoYWNmX3BlcmlvZCkgJT4lCiAgbXV0YXRlKHBlcmlvZF90b3RhbCA9IHN1bShjYXNlcykpICU+JQogIG11dGF0ZShwY3QgPSBjYXNlcy9wZXJpb2RfdG90YWwpICU+JQogIG11dGF0ZShwY3QyID0gY2FzZV93aGVuKHNleD09IkYiIH4gLXBjdCwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gcGN0KSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogICAgICAgICAgICAgICAgIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJQcmUtQUNGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYi4gYWNmIiB+ICJBQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2Q9PSJjLiBwb3N0LWFjZiIgfiAiUG9zdC1BQ0YiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9MCksIGxpbmV0eXBlPTIpICsKICBnZW9tX3BvaW50KGFlcyh4PXBjdDIseT1hZ2UsIGNvbG91cj1mY3RfcmVsZXZlbChhY2ZfcGVyaW9kLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByZS1BQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zdC1BQ0YiKSksIHN0YXQ9ImlkZW50aXR5IikgKwogIHNjYWxlX3hfY29udGludW91cyhsYWJlbHM9bGFiZWxfYWJzMiwgbGltaXRzID0gYygtMC4yLCAwLjIpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikpICsKICB0aGVtZV9ncmV5KGJhc2VfZmFtaWx5ID0gIkFwdG9zIikgKwogIGxhYnMoeD0gIjwtIEZlbWFsZSAgICAgICAgICAgICAgICBQZXJjZW50IG9mIGNhc2VzICAgICAgICAgICAgICBNYWxlIC0+IiwKICAgICAgIHk9IiIpICsKICB0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNS5wbmciKSkKCmBgYAoKCgpQcmVwYXJlIHRoZSBkYXRhc2V0cyBmb3IgbW9kZWxsaW5nCgpgYGB7cn0KCm1kYXRhIDwtIHdhcmRfaW5jICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgZ3JvdXBfYnkod2FyZCkgJT4lCiAgbXV0YXRlKHlfbnVtID0gcm93X251bWJlcigpKSAlPiUKICB1bmdyb3VwKCkKCgptZGF0YV9leHRyYXB1bG1vbmFyeSA8LSB3YXJkX2luYyAlPiUKICBmaWx0ZXIodGJfdHlwZT09Ik5vbi1QdWxtb25hcnkiKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbih5ZWFyICVpbiUgYygxOTUwOjE5NTYpIH4gImEuIHByZS1hY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTcpIH4gImIuIGFjZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgeWVhciAlaW4lIGMoMTk1ODoxOTYzKSB+ICJjLiBwb3N0LWFjZiIpKSAlPiUKICBncm91cF9ieSh3YXJkKSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKSAlPiUgCiAgZmlsdGVyKHllYXI8PTE5NjEpICNubyBkYXRhIGZvciAxOTYyIGFuZCAxOTYzCgoKI3NjYWZmb2xkIGZvciBvdmVyYWxsIHByZWRpY3Rpb25zCm92ZXJhbGxfc2NhZmZvbGQgPC0gbWRhdGEgJT4lCiAgICBzZWxlY3QoeWVhciwgeWVhcjIsIHlfbnVtLCBhY2ZfcGVyaW9kLCBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCB3YXJkLCBjYXNlcykgJT4lCiAgICBncm91cF9ieSh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QpICU+JQogICAgc3VtbWFyaXNlKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAgPSBzdW0ocG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCksCiAgICAgICAgICAgICAgY2FzZXMgPSBzdW0oY2FzZXMpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShpbmNfMTAwayA9IGNhc2VzL3BvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAqMTAwMDAwKSAlPiUKICAgIGxlZnRfam9pbihtZGF0YV9leHRyYXB1bG1vbmFyeSAlPiUgZ3JvdXBfYnkoeWVhcikgJT4lCiAgICAgICAgICAgICAgICBzdW1tYXJpc2UoY2FzZXNfZXh0cmFwdWxtb25hcnkgPSBzdW0oY2FzZXMpKSkgJT4lCiAgICBtdXRhdGUoaW5jXzEwMGtfZXh0cmFwdWxtb25hcnkgPSBjYXNlc19leHRyYXB1bG1vbmFyeS9wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKjEwMDAwMCkKCmBgYAoKCiMjIyA3LiBQdWxtb25hcnkgVEIgbW9kZWwKCiMjIyMgNy4xIEZpdCB0aGUgbW9kZWwgYW5kIHByaW9ycwoKVGhpcyBtb2RlbHMgdGhlIGNhc2Ugbm90aWZpY2F0aW9uIHJhdGUgb3ZlciB0aW1lLCB3aXRoIGEgc3RlcCBjaGFuZ2UgZm9yIHRoZSBpbnRlcnZlbnRpb24sIGFuZCBzbG9wZSBjaGFuZ2UgYWZ0ZXIgdGhlIGludGVydmVudGlvbi4KCldvcmsgb24gdGhlIHByaW9ycyBhIGJpdC4gV2Ugd2lsbCBidWlsZCB1cCBmcm9tIGxlc3MgY29tcGxleCB0byBtb3JlIGNvbXBsZXguCgphKSBpbnRlcmNlcHQgb25seSwgdG8gcHJlZGljdCBjb3VudCBvZiBjYXNlcwoKYXQgdGhlIGludGVyY2VwdCwgd2UgZXhwZWN0IHNvbWV3aGVyZSBhcm91bmQgMjUwMC4gV2Ugd2lsbCBzZXQgdGhlIHN0YW5kYXJkIGRldmlhdGlvbiB0byBib3RoIDAuNSBhbmQgMSB0byBjaGVjayB3aGF0IGl0IGxvb2tzIGxpa2UKCmBgYHtyfQojIAojIGMocHJpb3IobG9nbm9ybWFsKDcuNjAwOTAyLCAwLjUpKSwgI2xvZygyNTAwKSA9IDcuNjAwOTAyCiMgICBwcmlvcihsb2dub3JtYWwoNy42MDA5MDIsIDEpKSkgJT4lIAojICAgcGFyc2VfZGlzdCgpICU+JSAKIyAgIAojICAgZ2dwbG90KGFlcyh5ID0gcHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoLjUsIC45NSkpICsKIyAgIHNjYWxlX3lfZGlzY3JldGUoTlVMTCwgbGFiZWxzID0gc3RyX2MoImxvZ25vcm1hbChsb2coMjAwMCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDE1MDAwKSkKIyAKIyAKIyBwcmlvcihnYW1tYSgxLCAwLjAxKSkgJT4lCiMgICBwYXJzZV9kaXN0KCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHk9cHJpb3IsIGRpc3QgPSAuZGlzdCwgYXJncyA9IC5hcmdzKSkgKwojICAgc3RhdF9oYWxmZXllKC53aWR0aCA9IGMoMC41LCAwLjk1KSkKIyAKIyAjbm93IGZpdCB0byBhIG1vZGVsLCBhbmQgcGxvdCBzb21lIHByaW9yIHJlYWxpc2F0aW9ucwojIAojIG1fcHJpb3IxIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IxLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gdGliYmxlKGludGVyY2VwdD0xKSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9aW50ZXJjZXB0LCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWxzID0gY29tbWEpCgoKYGBgCgpOb3cgdHJ5IHRvIGFkZCBpbiBhIHRlcm0gZm9yIHRoZSBlZmZlY3Qgb2YgeV9udW0uIFdlIGFudGljcGF0ZSB0aGF0IHRoZSBudW1iZXIgb2YgY2FzZXMgd2lsbCBkZWNsaW5lIGJ5IGFib3V0IDEtNSUgcGVyIHllYXIuIEhvd2V2ZXIsIGFzIHdlIGFyZSBwcmV0dHkgdW5jZXJ0YWluIGFib3V0IHRoaXMsIHdlIHdpbGwganVzdCBlbmNvZGUgYSB3ZWFrbHkgcmVndWxhcmlzaW5nIHByaW9yIHRvIHJlc3RyaWN0IHRoZSB5ZWFyIHNpemUgdG8gc2Vuc2libGUgcmFuZ2VzLgoKYGBge3J9CiMgCiMgCiMgbV9wcmlvcjIgPC0gYnJtKAojICAgY2FzZXMgfiAwICsgSW50ZXJjZXB0ICsgeV9udW0sCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coMjAwMCksIDAuNSksIGNsYXNzID0gYiwgY29lZiA9IEludGVyY2VwdCkgKwojICAgICAgICAgICBwcmlvcihnYW1tYSgxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMC4wMSksIGNsYXNzID0gYiwgY29lZiA9IHlfbnVtKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IyLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQoKYGBgCgpOb3cgd2Ugd2FudCB0byBhZGQgaW4gYSBwcmlvciBmb3IgdGhlIGVmZmVjdCBvZiB0aGUgYWNmX2ludGVydmVudGlvbi4gV2UgYW50aWNpcGF0ZSB0aGUgcGVhayB0byBiZSBhbnl3aGVyZSBiZXR3ZWVuIG5vIGVmZmVjdCwgYW5kIGEgdHJpcGxpbmcKCmBgYHtyfQojIAojIG1fcHJpb3IzIDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3Iobm9ybWFsKGxvZygyMDAwKSwgMC41KSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiLCBjb2VmID0geV9udW0pICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMDAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3IzLAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVscyA9IGNvbW1hKQojIAoKCmBgYAoKTm93IHdlIGxvb2sgYW5kIHNlZSB3aGF0IGl0IGxvb2tzIGxpa2Ugd2l0aCB0aGUgaW50ZXJhY3Rpb25zCgpgYGB7cn0KIyAKIyBtX3ByaW9yNCA8LSBicm0oCiMgICBjYXNlcyB+IDAgKyBJbnRlcmNlcHQgKyB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBvdmVyYWxsX3NjYWZmb2xkLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDI1MDApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKQojICkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I0LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKQojIAojIAoKYGBgCgpOb3cgdHJ5IGFkZGluZyBpbiB0aGUgcmFuZG9tIGludGVyY2VwdHMKCmBgYHtyfQoKIyBjKHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMC41KSksICNsb2coNTApID0gMy45MTIwMjMKIyAgIHByaW9yKGxvZ25vcm1hbCgzLjkxMjAyMywgMSkpKSAlPiUgCiMgICBwYXJzZV9kaXN0KCkgJT4lIAojICAgCiMgICBnZ3Bsb3QoYWVzKHkgPSBwcmlvciwgZGlzdCA9IC5kaXN0LCBhcmdzID0gLmFyZ3MpKSArCiMgICBzdGF0X2hhbGZleWUoLndpZHRoID0gYyguNSwgLjk1KSkgKwojICAgc2NhbGVfeV9kaXNjcmV0ZShOVUxMLCBsYWJlbHMgPSBzdHJfYygibG9nbm9ybWFsKGxvZyg1MCksICIsIGMoMC41LCAxKSwgIikiKSwKIyAgICAgICAgICAgICAgICAgICAgZXhwYW5kID0gZXhwYW5zaW9uKGFkZCA9IDAuMSkpICsKIyAgIHhsYWIoZXhwcmVzc2lvbihleHAoaXRhbGljKHApKGJldGFbMF0pKSkpICsKIyAgIGNvb3JkX2NhcnRlc2lhbih4bGltID0gYygwLDQwMCkpCiMgCiMgCiMgbV9wcmlvcjUgPC0gYnJtKAojICAgY2FzZXMgfiB5X251bSArIGFjZl9wZXJpb2QgKyB5X251bTphY2ZfcGVyaW9kICsgKCAxIHwgd2FyZCksCiMgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAojICAgZGF0YSA9IG1kYXRhLAojICAgc2FtcGxlX3ByaW9yID0gIm9ubHkiLAojICAgcHJpb3IgPSBwcmlvcihub3JtYWwobG9nKDUwKSwgMSksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkKIyApCiMgCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNSwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gTkEpICU+JQojICAgZ2dwbG90KGFlcyh4PXllYXIsIHk9LmVwcmVkKSkgKwojICAgc3RhdF9oYWxmZXllKCkgKwojICAgc2NhbGVfeV9sb2cxMChsYWJlbD1jb21tYSkKIyAKIyBhZGRfZXByZWRfZHJhd3Mob2JqZWN0PW1fcHJpb3I1LAojICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGEsCiMgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSBOQSkgJT4lCiMgICBnZ3Bsb3QoYWVzKHg9eWVhciwgeT0uZXByZWQpKSArCiMgICBzdGF0X2hhbGZleWUoKSArCiMgICBzY2FsZV95X2xvZzEwKGxhYmVsPWNvbW1hKSArCiMgICBmYWNldF93cmFwKHdhcmR+LikKCmBgYAoKQW5kIGFkZCBpbiB0aGUgcmFuZG9tIHNsb3BlcwoKYGBge3J9CiMgCiMgbV9wcmlvcjYgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0gKyBhY2ZfcGVyaW9kICsgeV9udW06YWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpLAojICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgIGRhdGEgPSBtZGF0YSwKIyAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IiwKIyAgIHByaW9yID0gcHJpb3IoZ2FtbWEoMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKIyAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDAuMSksIGNsYXNzID0gYikgKwojICAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpICsKIyAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpCiMgKQojIAojIAojIAojIG1fcHJpb3I2IDwtIGJybSgKIyAgIGNhc2VzIH4gMCArIEludGVyY2VwdCArIHlfbnVtICsgYWNmX3BlcmlvZCArIHlfbnVtOmFjZl9wZXJpb2QgKyAoIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSwKIyAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICBkYXRhID0gbWRhdGEsCiMgICBzYW1wbGVfcHJpb3IgPSAib25seSIsCiMgICBwcmlvciA9IHByaW9yKG5vcm1hbChsb2coNTApLCAxKSwgY2xhc3MgPSBiLCBjb2VmID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgIHByaW9yKGdhbW1hKDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAwLjAxKSwgY2xhc3MgPSBiKSArCiMgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEwMCksIGNsYXNzPXNkKSArCiMgICAgICAgICAgIHByaW9yKGxraigyKSwgY2xhc3M9Y29yKQojICkKCgojIGFkZF9lcHJlZF9kcmF3cyhvYmplY3Q9bV9wcmlvcjYsCiMgICAgICAgICAgICAgICAgIG5ld2RhdGEgPSBtZGF0YSwKIyAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IE5BKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpCiMgCiMgYWRkX2VwcmVkX2RyYXdzKG9iamVjdD1tX3ByaW9yNiwKIyAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gfiggMSArIHlfbnVtICsgYWNmX3BlcmlvZCB8IHdhcmQpKSAlPiUKIyAgIGdncGxvdChhZXMoeD15ZWFyLCB5PS5lcHJlZCkpICsKIyAgIHN0YXRfaGFsZmV5ZSgpICsKIyAgIHNjYWxlX3lfbG9nMTAobGFiZWw9Y29tbWEpICsKIyAgIGZhY2V0X3dyYXAod2FyZH4uKQojIAojIHBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHJpb3I2LCBvdXRjb21lID0gaW5jXzEwMGssIAojICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIHJlX2Zvcm11bGEgPSBOQSkKIyAKIyBwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YSwgbW9kZWw9bV9wcmlvcjYsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0gKyBhY2ZfcGVyaW9kIHwgd2FyZCkpCgpgYGAKCgpJc3N1ZSBoZXJlIGlzIHRoZSBub24tY2VudHJlZCBwYXJhbWV0ZXJpc2F0aW9uIG9mIHRoZSBpbnRlcmNlcHQgcHJpb3IuLi4gRmVlbCBsaWtlIHRoaXMgaXMgYSBtb3JlIGludGVycHJldGFibGUgd2F5IHRvIHNldCBwcmlvcnMuLi4gYnV0IHdpbGwgcmV2ZXJ0IHRvIGNlbnRyZWQgcGFyYW1ldGVyaXNhdGlvbiBmb3IgdGhlIG1lYW50aW1lLgoKCmBgYHtyfQojIG1fY2VudGVyZWRfcHJpb3IgPC0gYnJtKAojICAgY2FzZXMgfiAxICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiMgICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhLAojICAgICAgICAgICAgICAgICAgIGZhbWlseSA9IG5lZ2Jpbm9taWFsKCksCiMgICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiMgICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LAojICAgICAgICAgICAgICAgICAgIHByaW9yID0gcHJpb3Iobm9ybWFsKDAsMTAwMCksIGNsYXNzID0gSW50ZXJjZXB0KSArCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpICsKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IobGtqKDIpLCBjbGFzcz1jb3IpLAojICAgICAgICAgICAgICAgICAgIHNhbXBsZV9wcmlvciA9ICJvbmx5IikKIyAKIyBwbG90KG1fY2VudGVyZWRfcHJpb3IpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9jZW50ZXJlZF9wcmlvciwgb3V0Y29tZSA9IGluY18xMDBrLCAKIyAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCByZV9mb3JtdWxhID0gTkEpCiMgCiMgcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGEsIG1vZGVsPW1fY2VudGVyZWRfcHJpb3IsIG91dGNvbWUgPSBpbmNfMTAwaywgCiMgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwKIyAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KCAxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQoKYGBgCgoKCgpMb29rIGF0IHRoZSBtZWFuIGFuZCB2YXJpYW5jZSBvZiBjb3VudHMgKGNvdW50cyBvZiBwdWxtb25hcnkgbm90aWZpY2F0aW9ucyBhcmUgd2hhdCB3ZSBhcmUgcHJlZGljdGluZykKCmBgYHtyfQoKI01lYW4gb2YgY291bnRzIHBlciB5ZWFyCm1lYW4obWRhdGEkY2FzZXMpCiN2YXJpYW5jZSBvZiBjb3VudHMgcGVyIHllYXIKdmFyKG1kYXRhJGNhc2VzKQoKYGBgCgoKCgoKUXVpdGUgYSBiaXQgb2Ygb3Zlci1kaXNwZXJzaW9uIGhlcmUsIHNvIG5lZ2F0aXZlIGJpbm9taWFsIGRpc3RyaWJ1dGlvbiBtaWdodCBiZSBhIGJldHRlciBjaG9pY2Ugb2YgZGlzdHJpYnV0aW9uYWwgZmFtaWx5IHRoYW4gUG9pc3Nvbi4KCkZpdCB0aGUgbW9kZWwgd2l0aCB0aGUgZGF0YQoKYGBge3J9CgptX3B1bG1vbmFyeSA8LSBicm0oCiAgY2FzZXMgfiAwICsgSW50ZXJjZXB0ICsgeV9udW0qYWNmX3BlcmlvZCArICgxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpICsgb2Zmc2V0KGxvZyhwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKSksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YSwKICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKICAgICAgICAgICAgICAgICAgc2VlZCA9IDEyMzQsCiAgICAgICAgICAgICAgICAgIGNoYWlucyA9IDQsIGNvcmVzID0gNCwKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxKSwgY2xhc3M9YiwgY29lZiA9ICJJbnRlcmNlcHQiKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZ2FtbWEoMC4wMSwgMC4wMSksIGNsYXNzID0gc2hhcGUpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYikgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGV4cG9uZW50aWFsKDEpLCBjbGFzcz1zZCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGxraig0KSwgY2xhc3M9Y29yKSwKICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOSkpCiAgCiNjaGVjayBtb2RlbCBkaWFnbm9zdGljcwpzdW1tYXJ5KG1fcHVsbW9uYXJ5KQpwbG90KG1fcHVsbW9uYXJ5KQoKcHBfY2hlY2sobV9wdWxtb25hcnksIHR5cGU9J2VjZGZfb3ZlcmxheScpCnByaW9yX3N1bW1hcnkobV9wdWxtb25hcnkpCgpgYGAKCk5pY2VyIHZlcnNpb24gb2YgdHJhY2UgcGxvdHMgZm9yIHN1cHBsZW1lbnRhbCBtYXRlcmlhbAoKYGBge3IsIGZpZy5oZWlnaHQ9MTYsIGZpZy53aWR0aD0xNn0KCmFzX2RyYXdzX2RmKG1fcHVsbW9uYXJ5KSAlPiUgCiAgYmF5ZXNwbG90OjptY21jX3Jhbmtfb3ZlcmxheShwYXJzID0gdmFycyhiX0ludGVyY2VwdDpzaGFwZSksCiAgICAgICAgICAgICBmYWNldF9hcmdzID0gbGlzdChuY29sID0gNCkpICsKICBzY2FsZV9jb2xvdXJfc2NpY29fZChwYWxldHRlID0gIm1hbmFndWEiLCBuYW1lID0gIkNoYWluIikgKwogIHRoZW1lX2dnZGlzdCgpKwogIHRoZW1lKHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSksCiAgICAgICAgbGVnZW5kLnBvc2l0aW9uID0gInRvcCIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNy5wbmciKSwgd2lkdGg9MTYsIGhlaWdodD0xNikKYGBgCgpOaWNlciB2ZXJzaW9uIG9mIHRhYmxlIG9mIHBhcmFtZXRlcnMgZm9yIHN1cHBsZW1lbnQKCmBgYHtyfQoKc3VtbWFyaXNlX2RyYXdzKG1fcHVsbW9uYXJ5KSAlPiUKICBtdXRhdGUoYWNyb3NzKGMobWVhbjplc3NfdGFpbCksIGNvbW1hLCBhY2N1cmFjeT0wLjAxKSkgJT4lCiAgd3JpdGVfY3N2KGhlcmUoImZpZ3VyZXMvczFfdGFibGUuY3N2IikpCgpgYGAKCgoKIyMjIyA3LjIgU3VtbWFyaXNlIGNoYW5nZSBpbiBDTlJzCgpTdW1tYXJpc2UgdGhlIHBvc3RlcmlvciBpbiBncmFwaGljYWwgZm9ybQoKYGBge3J9CgpmMWIgPC0gcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWwgPSBtX3B1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBvdXRjb21lID0gaW5jXzEwMGssIGdyb3VwaW5nX3Zhcj1OVUxMLAogICAgICAgICAgICAgICAgICAgICAgICAgICByZV9mb3JtdWxhID0gTkEpCiAgCmYxYgpgYGAKCk1ha2UgdGhpcyBpbnRvIGEgZmlndXJlIGNvbWJpbmVkIHdpdGggdGhlIG1hcCBvZiBlbXBpcmljYWwgZGF0YQoKYGBge3J9CgpmMWEgPC0gc3RfYXNfc2YobGVmdF9qb2luKHdhcmRfaW5jLCBnbGFzZ293X3dhcmRzXzE5NTEpKSAlPiUKICBmaWx0ZXIodGJfdHlwZT09IlB1bG1vbmFyeSIpICU+JQogIGdncGxvdCgpICsKICBnZW9tX3NmKGFlcyhmaWxsPWluY18xMDBrKSwgY29sb3VyPSJncmV5OTgiLCBsd2Q9MC4wMSkgKwogIGZhY2V0X3dyYXAoeWVhcn4uLCBuY29sID0gNykgKwogIHNjYWxlX2ZpbGxfc2NpY28obmFtZT0iQ05SIChwZXIgMTAwLDAwMCkiLAogICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGUgPSAiYWN0b24iLCBkaXJlY3Rpb24gPSAtMSkgKwogIHRoZW1lX2dyZXkoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gInRvcCIsCiAgICAgICAgI2xlZ2VuZC5rZXkud2lkdGggPSB1bml0KDEsICJjbSIpLAogICAgICAgIGxlZ2VuZC50aXRsZS5hbGlnbiA9IDAuNSwKICAgICAgICBheGlzLnRleHQueCA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLnRleHQueSA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBheGlzLmxpbmUgPSBlbGVtZW50X2JsYW5rKCksCiAgICAgICAgYXhpcy50aWNrcyA9IGVsZW1lbnRfYmxhbmsoKSwKICAgICAgICBwYW5lbC5iYWNrZ3JvdW5kID0gZWxlbWVudF9ibGFuaygpLAogICAgICAgIGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplPTEwKSkKCihmMWEgLyBmMWIpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpCgpnZ3NhdmUoaGVyZSgiZmlndXJlcy9mMS5wbmciKSwgd2lkdGg9NywgaGVpZ2h0PTgpCgpgYGAKClN1bW1hcnkgb2YgY2hhbmdlIGluIG5vdGlmaWNhdGlvbnMgbnVtZXJpY2FsbHkKCmBgYHtyfQoKb3ZlcmFsbF9jaGFuZ2UgPC0gc3VtbWFyaXNlX2NoYW5nZShtb2RlbF9kYXRhPW92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yPXBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsIGdyb3VwaW5nX3Zhcj1OVUxMLCByZV9mb3JtdWxhID0gTkEpCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKb3ZlcmFsbF9jaGFuZ2UgJT4lCiAga2VlcCgobmFtZXMoLikgJWluJSB0b2tlZXApKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoZXN0aW1hdGU6LnVwcGVyKSwgbnVtYmVyLCBhY2N1cmFjeT0wLjAxKSkgJT4lCiAgc2VsZWN0KG1lYXN1cmUsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCiAgCmBgYAoKCiMjIyMgNy4zIENvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsCgpOdW1iZXJzIG9mIHB1bG1vbmFyeSBUQiBjYXNlcyBhdmVydGVkIGNvbXBhcmVkIHRvIGNvdW50ZXJmYWN0dWFsIHBlciB5ZWFyLgoKYGBge3J9CgpvdmVyYWxsX3B1bG1vbmFyeV9jb3VudGVyZiA8LSBjYWxjdWxhdGVfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG92ZXJhbGxfc2NhZmZvbGQsIG1vZGVsPW1fcHVsbW9uYXJ5LCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCkKCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKVG90YWwgcHVsbW9uYXJ5IFRCIGNhc2VzIGF2ZXJ0ZWQgYmV0d2VlbiAxOTU4IGFuZCAxOTYzCgpgYGB7cn0KCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgpgYGAKCiMjIyMgNy40IENvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhaywgUlIubGV2ZWwsIGFuZCBSUi5zbG9wZQoKV2hhdCBhcmUgdGhlIGNvcnJlbGF0aW9ucyBiZXR3ZWVuIHBlYWssIGxldmVsLCBhbmQgc2xvcGU/CgpgYGB7cn0KCiNSUi5wZWFrIGhpc3RvZ3JhbQphIDwtIG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWVzdGltYXRlKSwgZmlsbD0iZGFya2JsdWUiLCBjb2xvdXI9ImRhcmtibHVlIiwgYWxwaGE9MC4zKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgbGFicyh4PSJSUi5wZWFrIiwKICAgICAgIHk9IiIpCgojUlIuIGxldmVsIGhpc3RvZ3JhbQpiIDwtIG92ZXJhbGxfY2hhbmdlJGxldmVsX2RyYXdzICAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9oaXN0b2dyYW0oYWVzKHg9ZXN0aW1hdGUpLCBmaWxsPSJkYXJrYmx1ZSIsIGNvbG91cj0iZGFya2JsdWUiLCBhbHBoYT0wLjMpKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IlJSLmxldmVsIiwKICAgICAgIHk9IiIpCgojUlIuc2xvcGUgaGlzdG9ncmFtCmMgPC0gb3ZlcmFsbF9jaGFuZ2Ukc2xvcGVfZHJhd3MgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGlzdG9ncmFtKGFlcyh4PWVzdGltYXRlKSwgZmlsbD0iZGFya2JsdWUiLCBjb2xvdXI9ImRhcmtibHVlIiwgYWxwaGE9MC4zKSsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArICAKICAjc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNikpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpICsKICBsYWJzKHg9IlJSLnNsb3BlIiwKICAgICAgIHk9IiIpCgoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIubGV2ZWwKY29yX3JyX3BlYWtfcnJfbGV2ZWwgPC0gcm91bmQoY29yKHBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRsZXZlbF9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIuc2xvcGUKY29yX3JyX3BlYWtfcnJfc2xvcGUgPC0gcm91bmQoY29yKHBsdWNrKG92ZXJhbGxfY2hhbmdlJHBlYWtfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKI0NvcnJlbGF0aW9uIGJldHdlZW4gUlIubGV2ZWwgYW5kIFJSLnNsb3BlCmNvcl9ycl9sZXZlbF9ycl9zbG9wZSA8LSByb3VuZChjb3IocGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpLCBwbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpLCBkaWdpdHMgPSAyKQoKCiNwbG90IG9mIGNvcnJlbGF0aW9uIGJldHdlZW4gUlIucGVhayBhbmQgUlIubGV2ZWwKZCA8LSBiaW5kX2NvbHMoUlIucGVhaz1wbHVjayhvdmVyYWxsX2NoYW5nZSRwZWFrX2RyYXdzJGVzdGltYXRlKSwgCiAgICAgICAgICBSUi5sZXZlbCA9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpKSAlPiUKICBnZ3Bsb3QoYWVzKHk9UlIucGVhaywgeCA9IFJSLmxldmVsKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIsIG1ldGhvZCA9ICJsbSIpICsKICBnZW9tX3RleHQoYWVzKHk9Mi4yLCB4PTAuNTgsIGxhYmVsPWNvcl9ycl9wZWFrX3JyX2xldmVsKSwgY29sb3VyPSJmaXJlYnJpY2siKSAgKwogIHNjYWxlX2ZpbGxfZ3JhZGllbnQoaGlnaD0ibGlnaHRibHVlMSIsbG93PSJkYXJrYmx1ZSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgojcGxvdCBvZiBjb3JyZWxhdGlvbiBiZXR3ZWVuIFJSLnBlYWsgYW5kIFJSLnNsb3BlCmUgPC0gYmluZF9jb2xzKFJSLnBlYWs9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkcGVha19kcmF3cyRlc3RpbWF0ZSksIAogICAgICAgICAgUlIuc2xvcGUgPXBsdWNrKG92ZXJhbGxfY2hhbmdlJHNsb3BlX2RyYXdzJGVzdGltYXRlKSkgJT4lCiAgZ2dwbG90KGFlcyh5PVJSLnBlYWssIHggPSBSUi5zbG9wZSkpICsKICBnZW9tX2hleCgpICsKICBnZW9tX3Ntb290aChzZT1GQUxTRSwgY29sb3VyPSJmaXJlYnJpY2siLCBtZXRob2QgPSAibG0iKSArCiAgZ2VvbV90ZXh0KGFlcyh5PTIuMSwgeD0wLjY1LCBsYWJlbD1jb3JfcnJfcGVha19ycl9zbG9wZSksIGNvbG91cj0iZmlyZWJyaWNrIikgICsKICAjc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNikpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKI3Bsb3Qgb2YgY29ycmVsYXRpb24gYmV0d2VlbiBSUi5sZXZlbCBhbmQgUlIuc2xvcGUKZiA8LSBiaW5kX2NvbHMoUlIubGV2ZWw9cGx1Y2sob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfZHJhd3MkZXN0aW1hdGUpLCAKICAgICAgICAgIFJSLnNsb3BlID1wbHVjayhvdmVyYWxsX2NoYW5nZSRzbG9wZV9kcmF3cyRlc3RpbWF0ZSkpICU+JQogIGdncGxvdChhZXMoeT1SUi5sZXZlbCwgeCA9IFJSLnNsb3BlKSkgKwogIGdlb21faGV4KCkgKwogIGdlb21fc21vb3RoKHNlPUZBTFNFLCBjb2xvdXI9ImZpcmVicmljayIsIG1ldGhvZCA9ICJsbSIpICsKICBnZW9tX3RleHQoYWVzKHk9MC43NSwgeD0wLjY1LCBsYWJlbD1jb3JfcnJfbGV2ZWxfcnJfc2xvcGUpLCBjb2xvdXI9ImZpcmVicmljayIpICArICAKICAjc2NhbGVfeF9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgNikpICsKICBzY2FsZV9maWxsX2dyYWRpZW50KGhpZ2g9ImxpZ2h0Ymx1ZTEiLGxvdz0iZGFya2JsdWUiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKCihwbG90X3NwYWNlcigpICsgcGxvdF9zcGFjZXIoKSArIGMpIC8KICAocGxvdF9zcGFjZXIoKSArIGIgKyBmKSAvCiAgKGEgKyBkICsgZSkKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M4LnBuZyIpLCB3aWR0aD04LCBoZWlnaHQ9OCkKCgoKYGBgCgoKIyMjIyA3LjUgV2FyZCBsZXZlbCBwdWxtb25hcnkgVEIgZXN0aW1hdGVzCgpQbG90IHRoZSBjb3VudGVyZmFjdHVhbCBhdCB3YXJkIGxldmVsCgpgYGB7cn0KCnBsb3RfY291bnRlcmZhY3R1YWwobW9kZWxfZGF0YSA9IG1kYXRhLCBtb2RlbD1tX3B1bG1vbmFyeSwgb3V0Y29tZSA9IGluY18xMDBrLCBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgCiAgICAgICAgICAgICAgICAgICAgZ3JvdXBpbmdfdmFyID0gd2FyZCwgd2FyZCwgcmVfZm9ybXVsYT0gfigxICsgeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zNi5wbmciKSwgd2lkdGg9MTYsIGhlaWdodD0xMikKCmBgYAoKU3VtbWFyeSBvZiBjaGFuZ2UgaW4gbm90aWZpY2F0aW9ucyBhdCB3YXJkIGxldmVsCgpgYGB7cn0KCndhcmRfY2hhbmdlIDwtIHN1bW1hcmlzZV9jaGFuZ2UobW9kZWxfZGF0YT1tZGF0YSwgbW9kZWw9bV9wdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3I9cG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlX2Zvcm11bGEgPSB+KDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkpCgojd2FudCB0byBrZWVwIHRoZSBzdW1tYXJ5IGVzdGltYXRlcyBoZXJlCnRva2VlcCA8LSBjKCJwZWFrX3N1bW1hcnkiLCAibGV2ZWxfc3VtbWFyeSIsICJzbG9wZV9zdW1tYXJ5IikKCiNzdW1tYXJ5IG1lYXN1cmVzIGluIGEgdGFibGUKd2FyZF9jaGFuZ2UgJT4lCiAga2VlcCgobmFtZXMoLikgJWluJSB0b2tlZXApKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMoZXN0aW1hdGU6LnVwcGVyKSwgbnVtYmVyLCBhY2N1cmFjeT0wLjAxKSkgJT4lCiAgc2VsZWN0KG1lYXN1cmUsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgZGF0YXRhYmxlKCkKCgojcGxvdCB0aGVzZSBpbiBhIGZpZ3VyZQp3YXJkX2VmZmVjdHMgPC0gd2FyZF9jaGFuZ2UgJT4lCiAga2VlcCgobmFtZXMoLikgJWluJSB0b2tlZXApKSAlPiUKICBiaW5kX3Jvd3MoKSAlPiUKICBiaW5kX3Jvd3Mob3ZlcmFsbF9jaGFuZ2UkcGVha19zdW1tYXJ5KSAlPiUKICBiaW5kX3Jvd3Mob3ZlcmFsbF9jaGFuZ2UkbGV2ZWxfc3VtbWFyeSkgJT4lCiAgYmluZF9yb3dzKG92ZXJhbGxfY2hhbmdlJHNsb3BlX3N1bW1hcnkpICU+JQogIG11dGF0ZV9hdCgudmFycyA9IHZhcnMoZXN0aW1hdGU6LnVwcGVyKSwgCiAgICAgICAgICAgIC5mdW5zID0gZnVucyhhcy5udW1lcmljKSkgJT4lCiAgc2VsZWN0KG1lYXN1cmUsIGV2ZXJ5dGhpbmcoKSkgJT4lCiAgbXV0YXRlKGVzdGltYXRlID0gYXMuZG91YmxlKGVzdGltYXRlKSkgJT4lCiAgZnVsbF9qb2luKGdsYXNnb3dfd2FyZHNfMTk1MSkgJT4lIAogIG11dGF0ZSh3YXJkMiA9IHBhc3RlMCh3YXJkX251bWJlciwgIi4gIiwgd2FyZCkpICU+JQogIG11dGF0ZSh3YXJkMiA9IGNhc2Vfd2hlbihpcy5uYSh3YXJkKSB+ICJPdmVyYWxsIiwKICAgICAgICAgICAgICAgICAgICAgICAgICBUUlVFIH4gd2FyZDIpKSAlPiUKICBzdF9hc19zZigpIAoKI2Z1bmN0aW9uIGZvciBwbG90dGluZyBjaG9yb3BsZXRoIG1hcHMKcGxvdF93YXJkX2VmZmVjdCA8LSBmdW5jdGlvbihkYXRhLCBtZWFzdXJlKXsKICB7e2RhdGF9fSAlPiUKICBmaWx0ZXIobWVhc3VyZSA9PSB7e21lYXN1cmV9fSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fc2YoYWVzKGZpbGw9ZXN0aW1hdGUpKSArCiAgZ2VvbV9zZl9sYWJlbChhZXMobGFiZWwgPSB3YXJkX251bWJlciksIHNpemU9MywgZmlsbD1OQSwgbGFiZWwuc2l6ZSA9IE5BLCBjb2xvdXI9ImJsYWNrIikgKwogIHNjYWxlX2ZpbGxfc2NpY28odHJhbnM9ImxvZyIsIHBhbGV0dGUgPSAicm9tYSIsIG1pZHBvaW50ID0gMCwgbGltaXRzPWMoMC41LDIuMjUpLAogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMC41LCAwLjc1LCAxLCAxLjUsIDIsIDIuNSksIGxhYmVscyA9IGMoMC41LCAwLjc1LCAxLCAxLjUsIDIsIDIuNSksCiAgICAgICAgICAgICAgICAgICBuYW1lPSJSZWxhdGl2ZSByYXRlIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpLAogICAgICAgIGF4aXMudGV4dC54PWVsZW1lbnRfdGV4dChhbmdsZT00NSwgaGp1c3Q9MSkpICsKICAgIGxhYnMoeD0iIiwgeT0iIikKfQoKI2Z1bmN0aW9uIGZvciBwbG90dGluZyBjYXRhcGlsbGVyIHBsb3RzCnBsb3Rfd2FyZF9jYXQgPC0gZnVuY3Rpb24oZGF0YSwgbWVhc3VyZSwgc2NhbGUpewoKICAgIGdncGxvdCgpICsKICAgIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpICsKICAgIGdlb21fcG9pbnRyYW5nZShkYXRhID0ge3tkYXRhfX0gJT4lICAgICAKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcihtZWFzdXJlPT17e21lYXN1cmV9fSkgJT4lCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIoIWlzLm5hKHdhcmQpKSwKICAgICAgICAgICAgICAgICAgICBhZXMoeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9ZmN0X3Jlb3JkZXIod2FyZDIsIGVzdGltYXRlKSwgY29sb3VyPWVzdGltYXRlKSkgKwogICAgZ2VvbV9wb2ludHJhbmdlKGRhdGEgPSB7e2RhdGF9fSAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBmaWx0ZXIobWVhc3VyZT09e3ttZWFzdXJlfX0pICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKGlzLm5hKHdhcmQpKSwKICAgICAgICAgICAgICAgICAgICBhZXMoeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCAKICAgICAgICAgICAgICAgICAgICAgIHg9d2FyZDIpLCBjb2xvdXI9ImJsYWNrIikgKwogICAgY29vcmRfZmxpcCgpICsKICAgIHNjYWxlX2NvbG91cl9zY2ljbyh0cmFucz0ibG9nIiwgcGFsZXR0ZSA9ICJyb21hIiwgbWlkcG9pbnQgPSAwLCBsaW1pdHM9YygwLjUsMi4yNSksIAogICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IGMoMC41LCAwLjc1LCAxLCAxLjUsIDIsIDIuNSksIGxhYmVscyA9IGMoMC41LCAwLjc1LCAxLCAxLjUsIDIsIDIuNSksCiAgICAgICAgICAgICAgICAgICAgICAgbmFtZT0iUmVsYXRpdmUgcmF0ZSIpICsKICAgIHNjYWxlX3lfY29udGludW91cygpICsKICAgIHRoZW1lX2dnZGlzdCgpICArCiAgICB0aGVtZShwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKSArCiAgICBsYWJzKHggPSAiIiwKICAgICAgICAgeSA9ICJSZWxhdGl2ZSByYXRlICg5NSUgVUkpIikrCiAgICBndWlkZXMoeCA9ICJheGlzX3RydW5jYXRlZCIsIHkgPSAiYXhpc190cnVuY2F0ZWQiKQp9CgoKCndhcmRfcGVha19pIDwtIHBsb3Rfd2FyZF9lZmZlY3QoZGF0YSA9IHdhcmRfZWZmZWN0cywgbWVhc3VyZSA9ICJSUi5wZWFrIikgKyBnZ3RpdGxlKCJQZWFrIGVmZmVjdCIpCndhcmRfbGV2ZWxfaSA8LSBwbG90X3dhcmRfZWZmZWN0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIubGV2ZWwiKSArIGdndGl0bGUoIkxldmVsIGVmZmVjdCIpCndhcmRfc2xvcGVfaSA8LSBwbG90X3dhcmRfZWZmZWN0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIuc2xvcGUiKSArIGdndGl0bGUoIlNsb3BlIGVmZmVjdCIpCgp3YXJkX3BlYWtfaWkgPC0gcGxvdF93YXJkX2NhdChkYXRhID0gd2FyZF9lZmZlY3RzLCBtZWFzdXJlID0gIlJSLnBlYWsiKSArIGdndGl0bGUoIlBlYWsgZWZmZWN0IikKd2FyZF9sZXZlbF9paSA8LSBwbG90X3dhcmRfY2F0KGRhdGEgPSB3YXJkX2VmZmVjdHMsIG1lYXN1cmUgPSAiUlIubGV2ZWwiKSArIGdndGl0bGUoIkxldmVsIGVmZmVjdCIpCndhcmRfc2xvcGVfaWkgPC0gcGxvdF93YXJkX2NhdChkYXRhID0gd2FyZF9lZmZlY3RzLCBtZWFzdXJlID0gIlJSLnNsb3BlIikgKyBnZ3RpdGxlKCJTbG9wZSBlZmZlY3QiKQoKczQgPC0gKHdhcmRfcGVha19pICsgd2FyZF9sZXZlbF9pICsgd2FyZF9zbG9wZV9pKSAvCiAgKHdhcmRfcGVha19paSArIHdhcmRfbGV2ZWxfaWkgKyB3YXJkX3Nsb3BlX2lpKQoKczRbWzFdXSA8LSBzNFtbMV1dICsgcGxvdF9sYXlvdXQodGFnX2xldmVsID0gJ25ldycpCnM0W1syXV0gPC0gczRbWzJdXSArIHBsb3RfbGF5b3V0KHRhZ19sZXZlbCA9ICduZXcnKQpzNCArIHBsb3RfYW5ub3RhdGlvbih0YWdfbGV2ZWxzID0gYygnQScsICcxJykpICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gJ2NvbGxlY3QnKSAmCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uPSdib3R0b20nLAogICAgICAgIGxlZ2VuZC5rZXkud2lkdGggPSB1bml0KDMsICJjbSIpKQoKCmdnc2F2ZShoZXJlKCJmaWd1cmVzL2YyLnBuZyIpLCB3aWR0aCA9IDE2LCBoZWlnaHQ9MTIpCgpgYGAKCkNhbGN1bGF0ZSB0aGUgY291bnRlcmZhY3R1YWwgcGVyIHdhcmQKCmBgYHtyfQoKd2FyZF9wdWxtb25hcnlfY291bnRlcmYgPC0gY2FsY3VsYXRlX2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YSwgbW9kZWw9bV9wdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvciA9IHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXAsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBncm91cGluZ192YXIgPSB3YXJkLCByZV9mb3JtdWxhPX4oMSArIHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSkKCndhcmRfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBkYXRhdGFibGUoKQoKCmBgYAoKT3ZlcmFsbCBjb3VudGVyZmFjdHVhbCBwZXIgd2FyZAoKYGBge3J9Cgp3YXJkX3B1bG1vbmFyeV9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgpgYGAKCgoKIyMjIDguIEV4dHJhLXB1bG1vbmFyeSBUQiBub3RpZmljYXRpb25zCgpOb3cgd2Ugd2lsbCBtb2RlbCB0aGUgZXh0cmEtcHVsbW9uYXJ5IFRCIG5vdGlmaWNhdGlvbiByYXRlLiBTdHJ1Z2dsaW5nIGEgYml0IHdpdGggbmVnYXRpdmUgYmlub21pYWwgbW9kZWwsIHNvIHJldmVydCB0byBQb2lzc29uLgoKIyMjIyA4LjEgRml0IHRoZSBtb2RlbAoKYGBge3J9CgptX2V4dHJhcHVsbW9uYXJ5IDwtIGJybSgKICBjYXNlcyB+IDEgKyB5X251bSphY2ZfcGVyaW9kICsgKDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKICAgICAgICAgICAgICAgICAgZGF0YSA9IG1kYXRhX2V4dHJhcHVsbW9uYXJ5LAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LAogICAgICAgICAgICAgICAgICBwcmlvciA9IHByaW9yKG5vcm1hbCgwLDEwMDApLCBjbGFzcyA9IEludGVyY2VwdCkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3Iobm9ybWFsKDAsIDEpLCBjbGFzcyA9IGIpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihleHBvbmVudGlhbCgxKSwgY2xhc3M9c2QpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihsa2ooMiksIGNsYXNzPWNvcikpCgpzdW1tYXJ5KG1fZXh0cmFwdWxtb25hcnkpCnBsb3QobV9leHRyYXB1bG1vbmFyeSkKcHBfY2hlY2sobV9leHRyYXB1bG1vbmFyeSwgdHlwZT0nZWNkZl9vdmVybGF5JykKCmBgYAoKIyMjIyA4LjIgU3VtbWFyeSBvZiBjaGFuZ2UKClN1bW1hcmlzZSBpbiBwbG90CgpgYGB7cn0KcGxvdF9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gb3ZlcmFsbF9zY2FmZm9sZCAlPiUgZmlsdGVyKHllYXI8PTE5NjEpLCBtb2RlbD1tX2V4dHJhcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgb3V0Y29tZT1pbmNfMTAwa19leHRyYXB1bG1vbmFyeSwgcmVfZm9ybXVsYSA9IE5BKSArCiAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCw1MCkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3M5LnBuZyIpLCB3aWR0aD0xMCkKCmBgYAoKU3VtbWFyaXNlIG51bWVyaWNhbGx5LgoKYGBge3J9CgpvdmVyYWxsX2NoYW5nZV9leHRyYXB1bG1vbmFyeSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGE9b3ZlcmFsbF9zY2FmZm9sZCwgbW9kZWw9bV9leHRyYXB1bG1vbmFyeSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcG9wdWxhdGlvbl9kZW5vbWluYXRvcj1wb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwLCBncm91cGluZ192YXI9TlVMTCwgcmVfZm9ybXVsYSA9IE5BKQoKI3dhbnQgdG8ga2VlcCB0aGUgc3VtbWFyeSBlc3RpbWF0ZXMgaGVyZQp0b2tlZXAgPC0gYygicGVha19zdW1tYXJ5IiwgImxldmVsX3N1bW1hcnkiLCAic2xvcGVfc3VtbWFyeSIpCgojc3VtbWFyeSBtZWFzdXJlcyBpbiBhIHRhYmxlCm92ZXJhbGxfY2hhbmdlX2V4dHJhcHVsbW9uYXJ5ICU+JQogIGtlZXAobmFtZXMoLikgJWluJSB0b2tlZXApICU+JQogIGJpbmRfcm93cygpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKYGBgCgojIyMjIDguMyBDb21wYXJlZCB0byBjb3VudGVyZmFjdHVhbAoKTnVtYmVycyBvZiBleHRyYS1wdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBvdmVyYWxsLgoKYGBge3J9CgpvdmVyYWxsX2VwX2NvdW50ZXJmIDwtIGNhbGN1bGF0ZV9jb3VudGVyZmFjdHVhbChtb2RlbF9kYXRhID0gbWRhdGFfZXh0cmFwdWxtb25hcnksIG1vZGVsPW1fZXh0cmFwdWxtb25hcnksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBvcHVsYXRpb25fZGVub21pbmF0b3IgPSBwb3B1bGF0aW9uX3dpdGhvdXRfaW5zdF9zaGlwKQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3QgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGNhc2VzX2F2ZXJ0ZWQ6Y2FzZXNfYXZlcnRlZC51cHBlciwgZGlmZl9pbmMxMDBrOmRpZmZfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjEsIGJpZy5tYXJrID0gIiwiKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhycl9pbmMxMDBrOnJyX2luYzEwMGsudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4wMSkpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgZGF0YXRhYmxlKCkKCmBgYAoKVG90YWwgZXh0cmFwdWxtb25hcnkgVEIgY2FzZXMgYXZlcnRlZCBiZXR3ZWVuIDE5NTggYW5kIDE5NjMKCmBgYHtyfQoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIGRhdGF0YWJsZSgpCgoKYGBgCgpNYWtlIGludG8gVGFibGUgMgoKCmBgYHtyfQpiaW5kX3Jvd3MoCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUobW9kZWwgPSAiUFRCX3dhcmQiKSwKCm92ZXJhbGxfcHVsbW9uYXJ5X2NvdW50ZXJmJGNvdW50ZXJfcG9zdF9vdmVyYWxsICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgbXV0YXRlKG1vZGVsID0gIlBUQl9vdmVyYWxsIiksCgpvdmVyYWxsX2VwX2NvdW50ZXJmJGNvdW50ZXJfcG9zdCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyLCBkaWZmX2luYzEwMGs6ZGlmZl9pbmMxMDBrLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHJyX2luYzEwMGs6cnJfaW5jMTAway51cHBlciksIG51bWJlcl9mb3JtYXQoYWNjdXJhY3kgPSAwLjAxKSkpICU+JQogIG11dGF0ZShhY3Jvc3MoYyhwY3RfY2hhbmdlOnBjdF9jaGFuZ2UudXBwZXIpLCBwZXJjZW50LCBhY2N1cmFjeT0wLjEpKSAlPiUKICBtdXRhdGUobW9kZWwgPSAiRVBUQiIpLAoKb3ZlcmFsbF9lcF9jb3VudGVyZiRjb3VudGVyX3Bvc3Rfb3ZlcmFsbCAlPiUKICBtdXRhdGUoYWNyb3NzKGMoY2FzZXNfYXZlcnRlZDpjYXNlc19hdmVydGVkLnVwcGVyKSwgbnVtYmVyX2Zvcm1hdChhY2N1cmFjeSA9IDAuMSwgYmlnLm1hcmsgPSAiLCIpKSkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlciksIHBlcmNlbnQsIGFjY3VyYWN5PTAuMSkpICU+JQogIG11dGF0ZShtb2RlbCA9ICJFUFRCIG92ZXJhbGwiKQoKKSAlPiUKICBzZWxlY3QobW9kZWwsIHllYXIsIGRpZmZfaW5jMTAwaywgZGlmZl9pbmMxMDBrLmxvd2VyOnJyX2luYzEwMGsudXBwZXIsIAogICAgICAgICBjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIsCiAgICAgICAgIHBjdF9jaGFuZ2U6cGN0X2NoYW5nZS51cHBlcikgJT4lCiAgdHJhbnNtdXRlKG1vZGVsPW1vZGVsLCB5ZWFyPXllYXIsCiAgICAgICAgICAgIGRpZmZfY25yID0gZ2x1ZSgie2RpZmZfaW5jMTAwa30gKHtkaWZmX2luYzEwMGsubG93ZXJ9IHRvIHtkaWZmX2luYzEwMGsudXBwZXJ9KSIpLAogICAgICAgICAgICByciA9IGdsdWUoIntycl9pbmMxMDBrfSAoe3JyX2luYzEwMGsubG93ZXJ9IHRvIHtycl9pbmMxMDBrLnVwcGVyfSkiKSwKICAgICAgICAgICAgY2FzZXNfYXZlcnRlZCA9IGdsdWUoIntjYXNlc19hdmVydGVkfSAoe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWUoIntwY3RfY2hhbmdlfSAoe3BjdF9jaGFuZ2UubG93ZXJ9IHRvIHtwY3RfY2hhbmdlLnVwcGVyfSkiKSkgJT4lCiAgd3JpdGVfY3N2KGhlcmUoImZpZ3VyZXMvdGFibGUyLmNzdiIpKQoKCgpgYGAKCgoKCiMjIyMgOC40IFdhcmQtbGV2ZWwgZXh0cmEtcHVsbW9uYXJ5IHN1bW1hcmllcwoKV2FyZC1sZXZlbCBleHRyYS1wdWxtb25hcnkgZXN0aW1hdGVzIGluIGdyYXBoaWNhbCBmb3JtLgoKYGBge3J9CgpwbG90X2NvdW50ZXJmYWN0dWFsKG1vZGVsX2RhdGEgPSBtZGF0YV9leHRyYXB1bG1vbmFyeSwgbW9kZWw9bV9leHRyYXB1bG1vbmFyeSwgb3V0Y29tZSA9IGluY18xMDBrLCAKICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyID0gd2FyZCxyZV9mb3JtdWxhID1+KHlfbnVtKmFjZl9wZXJpb2QgfCB3YXJkKSwgCiAgICAgICAgICAgICAgICAgICAgd2FyZCkgKyBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzPSBjKDAsNzUpKQogIApnZ3NhdmUoaGVyZSgiZmlndXJlcy9zMTAucG5nIiksIHdpZHRoPTEwLCBoZWlnaHQ9MTIpCgpgYGAKCk51bWVyaWNhbCBzdW1tYXJ5LgoKYGBge3J9Cgp3YXJkX2NoYW5nZV9leHRyYXB1bG1vbmFyeSA8LSBzdW1tYXJpc2VfY2hhbmdlKG1vZGVsX2RhdGEgPSBtZGF0YV9leHRyYXB1bG1vbmFyeSwgbW9kZWwgPSBtX2V4dHJhcHVsbW9uYXJ5LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwb3B1bGF0aW9uX2Rlbm9taW5hdG9yID0gcG9wdWxhdGlvbl93aXRob3V0X2luc3Rfc2hpcCwgZ3JvdXBpbmdfdmFyPXdhcmQsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVfZm9ybXVsYSA9IH4oeV9udW0qYWNmX3BlcmlvZCB8IHdhcmQpKSAKCiN3YW50IHRvIGtlZXAgdGhlIHN1bW1hcnkgZXN0aW1hdGVzIGhlcmUKdG9rZWVwIDwtIGMoInBlYWtfc3VtbWFyeSIsICJsZXZlbF9zdW1tYXJ5IiwgInNsb3BlX3N1bW1hcnkiKQoKI3N1bW1hcnkgbWVhc3VyZXMgaW4gYSB0YWJsZQp3YXJkX2NoYW5nZV9leHRyYXB1bG1vbmFyeSAgJT4lCiAga2VlcChuYW1lcyguKSAlaW4lIHRva2VlcCkgJT4lCiAgYmluZF9yb3dzKCkgJT4lCiAgbXV0YXRlKGFjcm9zcyhjKGVzdGltYXRlOi51cHBlciksIG51bWJlciwgYWNjdXJhY3k9MC4wMSkpICU+JQogIHNlbGVjdChtZWFzdXJlLCBldmVyeXRoaW5nKCkpICU+JQogIGRhdGF0YWJsZSgpCgoKCmBgYAoKCiMjIyA5LiBBZ2Utc2V4IG1vZGVsCgojIyMjIDkuMSBGSXQgdGhlIG1vZGVsCgpGaXQgdGhlIG1vZGVsCgooTm90IHJld3JpdHRlbiB0aGUgZnVuY3Rpb25zIGZvciB0aGlzIHlldCkKCmBgYHtyfQoKbWRhdGFfYWdlX3NleCA8LSBjYXNlc19ieV9hZ2Vfc2V4ICU+JQogIGZpbHRlcih0Yl90eXBlPT0iUHVsbW9uYXJ5IikgJT4lCiAgbXV0YXRlKGFjZl9wZXJpb2QgPSBjYXNlX3doZW4oeWVhciAlaW4lIGMoMTk1MDoxOTU2KSB+ICJhLiBwcmUtYWNmIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB5ZWFyICVpbiUgYygxOTU3KSB+ICJiLiBhY2YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHllYXIgJWluJSBjKDE5NTg6MTk2MykgfiAiYy4gcG9zdC1hY2YiKSkgJT4lCiAgbXV0YXRlKHllYXIyID0geWVhciswLjUpICU+JQogIGdyb3VwX2J5KGFnZSwgc2V4KSAlPiUKICBtdXRhdGUoeV9udW0gPSByb3dfbnVtYmVyKCkpICU+JQogIHVuZ3JvdXAoKQoKbV9hZ2Vfc2V4IDwtIGJybSgKICBjYXNlcyB+IHlfbnVtICsgKGFjZl9wZXJpb2QpKihhZ2Uqc2V4KSArIChhY2ZfcGVyaW9kOnlfbnVtKSooYWdlKnNleCksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBtZGF0YV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICBmYW1pbHkgPSBuZWdiaW5vbWlhbCgpLAogICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKICAgICAgICAgICAgICAgICAgY2hhaW5zID0gNCwgY29yZXMgPSA0LCAKICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxKSwgY2xhc3MgPSBJbnRlcmNlcHQpICsKICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihnYW1tYSgwLjAxLCAwLjAxKSwgY2xhc3MgPSBzaGFwZSkgKwogICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKG5vcm1hbCgwLCAxKSwgY2xhc3MgPSBiKSkKCnN1bW1hcnkobV9hZ2Vfc2V4KQpwbG90KG1fYWdlX3NleCkKcHBfY2hlY2sobV9hZ2Vfc2V4LCB0eXBlPSdlY2RmX292ZXJsYXknKQoKYGBgCgpTdW1tYXJpc2UgcG9zdGVyaW9yCgoKYGBge3J9CgojcG9zdGVyaW9yIGRyYXdzLCBhbmQgc3VtbWFyaXNlCmFnZV9zZXhfc3VtbWFyeSA8LSBtZGF0YV9hZ2Vfc2V4ICU+JQogIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFjZl9wZXJpb2QsIGFnZSwgc2V4KSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKQoKI2NyZWF0ZSB0aGUgY291bnRlcmZhY3R1YWwgKG5vIGludGVydmVudGlvbiksIGFuZCBzdW1tYXJpc2UKYWdlX3NleF9jb3VudGVyZmFjdCA8LSAKICB0aWJibGUoeWVhciA9IG1kYXRhX2FnZV9zZXgkeWVhciwKICAgICAgICAgeWVhcjIgPSBtZGF0YV9hZ2Vfc2V4JHllYXIyLAogICAgICAgICB5X251bSA9IG1kYXRhX2FnZV9zZXgkeV9udW0sCiAgICAgICAgIGFnZSA9IG1kYXRhX2FnZV9zZXgkYWdlLAogICAgICAgICBzZXggPSBtZGF0YV9hZ2Vfc2V4JHNleCwKICAgICAgICAgYWNmX3BlcmlvZCA9IGZhY3RvcigiYS4gcHJlLWFjZiIpKSAlPiUKICBhZGRfZXByZWRfZHJhd3MobV9hZ2Vfc2V4KSAlPiUKICBncm91cF9ieSh5ZWFyMiwgYWNmX3BlcmlvZCwgYWdlLCBzZXgpICU+JQogIG1lYW5fcWkoKSAlPiUKICBtdXRhdGUoYWNmX3BlcmlvZCA9IGNhc2Vfd2hlbihhY2ZfcGVyaW9kPT0iYS4gcHJlLWFjZiIgfiAiQmVmb3JlIEludGVydmVudGlvbiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09ImMuIHBvc3QtYWNmIiB+ICJQb3N0IEludGVydmVudGlvbiIpKSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgCgoKCmFnZV9zZXhfc3VtbWFyeSAlPiUKICB1bmdyb3VwKCkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09ICJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09ICJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcmliYm9uKGFlcyh5bWluPS5lcHJlZC5sb3dlciwgeW1heD0uZXByZWQudXBwZXIsIHg9eWVhcjIsIGdyb3VwID0gYWNmX3BlcmlvZCwgZmlsbD1hY2ZfcGVyaW9kKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9yaWJib24oZGF0YSA9IGFnZV9zZXhfY291bnRlcmZhY3QgJT4lIGZpbHRlcih5ZWFyPj0xOTU2KSwgCiAgICAgICAgICAgICAgYWVzKHltaW49LmVwcmVkLmxvd2VyLCB5bWF4PS5lcHJlZC51cHBlciwgeD15ZWFyMiwgZmlsbD0iQ291bnRlcmZhY3R1YWwiKSwgYWxwaGE9MC41KSArCiAgZ2VvbV9saW5lKGRhdGEgPSBhZ2Vfc2V4X2NvdW50ZXJmYWN0ICU+JSBmaWx0ZXIoeWVhcj49MTk1NiksIAogICAgICAgICAgICAgIGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgY29sb3VyPSJDb3VudGVyZmFjdHVhbCIpKSArCiAgZ2VvbV9saW5lKGFlcyh5PS5lcHJlZCwgeD15ZWFyMiwgZ3JvdXA9YWNmX3BlcmlvZCwgIGNvbG91cj1hY2ZfcGVyaW9kKSkgKwogIGdlb21fcG9pbnQoZGF0YSA9IG1kYXRhX2FnZV9zZXggJT4lCiAgdW5ncm91cCgpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSAiTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSAiRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhY2ZfcGVyaW9kID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJhLiBwcmUtYWNmIiB+ICJCZWZvcmUgSW50ZXJ2ZW50aW9uIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYi4gYWNmIiB+ICJDb3VudGVyZmFjdHVhbCIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iYy4gcG9zdC1hY2YiIH4gIlBvc3QgSW50ZXJ2ZW50aW9uIikpJT4lCiAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QyID0gY2FzZV93aGVuKGFjZl9wZXJpb2Q9PSJCZWZvcmUgSW50ZXJ2ZW50aW9uIiB+ICJQcmUtQUNGIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY2ZfcGVyaW9kPT0iQ291bnRlcmZhY3R1YWwiIH4gIkFDRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZD09IlBvc3QgSW50ZXJ2ZW50aW9uIiB+ICJQb3N0LUFDRiIpKSwgCiAgYWVzKHk9Y2FzZXMsIHg9eWVhcjIsIHNoYXBlPWZjdF9yZWxldmVsKGFjZl9wZXJpb2QyLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIlByZS1BQ0YiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIkFDRiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAiUG9zdC1BQ0YiKSksIHNpemU9MikgKwogIGdlb21fdmxpbmUoYWVzKHhpbnRlcmNlcHQ9YWNmX2VuZCksIGxpbmV0eXBlPTMpICsKICBnZ2g0eDo6ZmFjZXRfZ3JpZDIoYWdlfnNleCwgc2NhbGVzID0gImZyZWVfeSIsIGluZGVwZW5kZW50ID0gInkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHM9Y29tbWEpICsKICBzY2FsZV94X2NvbnRpbnVvdXMobGFiZWxzID0geWVhcl9sYWJlbHMsCiAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHllYXJfbGFiZWxzLAogICAgICAgICAgICAgICAgICAgICBndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXMgPSBjKCIjREUwRDkyIiwgImdyZXk1MCIsICIjNEQ2Q0ZBIikgLCBuYW1lPSJNb2RlbCBlc3RpbWF0ZXM6IikgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0RFMEQ5MiIsICJncmV5NTAiLCAiIzRENkNGQSIpICwgbmFtZT0iTW9kZWwgZXN0aW1hdGVzOiIpICsKICBzY2FsZV9zaGFwZV9kaXNjcmV0ZShuYW1lPSJFbXByaWNhbCBkYXRhIChwZXJpb2QpOiIsIG5hLnRyYW5zbGF0ZSA9IEYpICsKICBsYWJzKAogICAgeCA9ICJZZWFyIiwKICAgIHkgPSAiQ2FzZSBub3RpZmljYXRpb25zIChuKSIsCiAgICBjYXB0aW9uID0gIk1hc3MgbWluaWF0dXJlIFgtcmF5IGNhbXBhaWduIHBlcmlvZCBiZXR3ZWVuIGRhc2hlZCBsaW5lcyAoMTF0aCBNYXJjaC0xMnRoIEFwcmlsIDE5NTcpIgogICkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLCAgICAgICAgICAKICAgICAgICBsZWdlbmQuYm94PSJ2ZXJ0aWNhbCIsIAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCiAgCmdnc2F2ZShoZXJlKCJmaWd1cmVzL3MxMi5wbmciKSwgaGVpZ2h0PTEwKQoKYGBgCgojIyMjIDkuMiBTdW1tYXJ5IG9mIGltcGFjdCBvZiBpbnRlcnZlbnRpb24KCkNhbGN1bGF0ZSBzdW1tYXJ5IGVmZmVjdHMKCmBgYHtyfQoKI1BlYWsKb3V0X2FnZV9zZXhfMSA8LSBjcm9zc2luZyhtZGF0YV9hZ2Vfc2V4ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtID09IDgpLAogICAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYi4gYWNmIikpCgpwZWFrX2RyYXdzX2FnZV9zZXggPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXRfYWdlX3NleF8xLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSBtX2FnZV9zZXgpICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQogIApwZWFrX3N1bW1hcnlfYWdlX3NleCA8LSBwZWFrX2RyYXdzX2FnZV9zZXggJT4lCiAgICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGVzdGltYXRlKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnBlYWsiKQoKCiNMZXZlbAogCm91dF9hZ2Vfc2V4XzIgPC0gY3Jvc3NpbmcobWRhdGFfYWdlX3NleCAlPiUgCiAgICAgICAgICAgICAgICAgICAgICBzZWxlY3QoeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgIGZpbHRlcih5X251bSA9PSA5KSwKICAgICAgICAgICAgICAgICAgICAgIGFjZl9wZXJpb2QgPSBjKCJhLiBwcmUtYWNmIiwgImMuIHBvc3QtYWNmIikpCiAgCmxldmVsX2RyYXdzX2FnZV9zZXggPC0gYWRkX2VwcmVkX2RyYXdzKG5ld2RhdGEgPSBvdXRfYWdlX3NleF8yLAogICAgICAgICAgICAgICAgICBvYmplY3QgPSBtX2FnZV9zZXgpICU+JQogICAgYXJyYW5nZSh5X251bSwgLmRyYXcpICU+JQogICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgIHN1bW1hcmlzZShlc3RpbWF0ZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKICAKbGV2ZWxfc3VtbWFyeV9hZ2Vfc2V4IDwtIGxldmVsX2RyYXdzX2FnZV9zZXggJT4lCiAgICBncm91cF9ieShhZ2UsIHNleCkgJT4lCiAgICBtZWFuX3FpKGVzdGltYXRlKSAlPiUKICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLmxldmVsIikKCiNTbG9wZQoKb3V0X2FnZV9zZXhfMyA8LSBjcm9zc2luZyhtZGF0YV9hZ2Vfc2V4ICU+JSAKICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgZmlsdGVyKHlfbnVtICVpbiUgYyg5LDE0KSksCiAgICAgICAgICAgICAgICAgICAgYWNmX3BlcmlvZCA9IGMoImEuIHByZS1hY2YiLCAiYy4gcG9zdC1hY2YiKSkKICAKc2xvcGVfZHJhd3NfYWdlX3NleCA8LSBhZGRfZXByZWRfZHJhd3MobmV3ZGF0YSA9IG91dF9hZ2Vfc2V4XzMsCiAgICAgICAgICAgICAgICAgIG9iamVjdCA9IG1fYWdlX3NleCkgJT4lCiAgICAgICAgYXJyYW5nZSh5X251bSkgJT4lCiAgICAgICAgdW5ncm91cCgpICU+JQogICAgICAgIGdyb3VwX2J5KC5kcmF3LCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgIHN1bW1hcmlzZShzbG9wZSA9IGxhc3QoLmVwcmVkKS9maXJzdCguZXByZWQpKSAlPiUKICAgICAgICB1bmdyb3VwKCkgJT4lCiAgICAgICAgZ3JvdXBfYnkoLmRyYXcsIGFnZSwgc2V4KSAlPiUKICAgICAgICBzdW1tYXJpc2UoZXN0aW1hdGUgPSBsYXN0KHNsb3BlKS9maXJzdChzbG9wZSkpICU+JQogICAgICAgIG11dGF0ZShtZWFzdXJlID0gIlJSLnNsb3BlIikKICAKc2xvcGVfc3VtbWFyeV9hZ2Vfc2V4IDwtIHNsb3BlX2RyYXdzX2FnZV9zZXggJT4lCiAgICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgICBtZWRpYW5fcWkoZXN0aW1hdGUpICU+JQogICAgICBtdXRhdGUobWVhc3VyZSA9ICJSUi5zbG9wZSIpCgpgYGAKCgpOdW1lcmljYWwgc3VtbWFyeSBvZiB0aGVzZSBzdW1tYXJ5IHJlc3VsdHMKCmBgYHtyfQoKYmluZF9yb3dzKAogIHBlYWtfc3VtbWFyeV9hZ2Vfc2V4LCBsZXZlbF9zdW1tYXJ5X2FnZV9zZXgsIHNsb3BlX3N1bW1hcnlfYWdlX3NleAopICU+JQogIG11dGF0ZShhY3Jvc3MoYyhlc3RpbWF0ZToudXBwZXIpLCBudW1iZXIsIGFjY3VyYWN5PTAuMDEpKSAlPiUKICBzZWxlY3QobWVhc3VyZSwgZXZlcnl0aGluZygpKSAlPiUKICBkYXRhdGFibGUoKQoKCgpgYGAKCkFzIGEgZmlndXJlCgpgYGB7cn0KCnBlYWtfZ19hZ2Vfc2V4IDwtIHBlYWtfc3VtbWFyeV9hZ2Vfc2V4ICU+JQogIG11dGF0ZShzZXggPSBjYXNlX3doZW4oc2V4PT0iTSIgfiAiTWFsZSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBzZXg9PSJGIiB+ICJGZW1hbGUiKSkgJT4lCiAgbXV0YXRlKGFnZSA9IGNhc2Vfd2hlbihhZ2U9PSIwMF8wNSIgfiAiMCB0byA1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIwNl8xNSIgfiAiMDYgdG8gMTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjE2XzI1IiB+ICIxNiB0byAyNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMjZfMzUiIH4gIjI2IHRvIDM1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIzNl80NSIgfiAiMzYgdG8gNDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjQ2XzU1IiB+ICI0NiB0byA1NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNTZfNjUiIH4gIjU2IHRvIDY1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI2NSsiIH4gIjY1ICYgdXAgeSIpKSAlPiUKICBnZ3Bsb3QoKSArCiAgZ2VvbV9obGluZShhZXMoeWludGVyY2VwdD0xKSwgbGluZXR5cGU9MikrCiAgZ2VvbV9wb2ludHJhbmdlKGFlcyh4PWFnZSwgeT1lc3RpbWF0ZSwgeW1pbj0ubG93ZXIsIHltYXg9LnVwcGVyLCBncm91cD1zZXgsIGNvbG91cj1zZXgsIHNoYXBlPXNleCksCiAgICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjUpKSArCiAgc2NhbGVfY29sb3VyX21hbnVhbCh2YWx1ZXMgPSBjKCIjQ0Q3QUM1IiwgImNhZGV0Ymx1ZTMiKSwgbmFtZT0iIikgKwogIHNjYWxlX3NoYXBlKG5hbWU9IiIpICsKICBsYWJzKHg9IiIsCiAgICAgICB5PSJSZWxhdGl2ZSByYXRlICg5NSUgVUkpIikgKwogIHRoZW1lX2dnZGlzdCgpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwKICAgICAgICBwYW5lbC5ib3JkZXIgPSBlbGVtZW50X3JlY3QoY29sb3VyID0gImdyZXk3OCIsIGZpbGw9TkEpKQoKI2xldmVsIHBsb3QKbGV2ZWxfZ19hZ2Vfc2V4IDwtIGxldmVsX3N1bW1hcnlfYWdlX3NleCAlPiUKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21faGxpbmUoYWVzKHlpbnRlcmNlcHQ9MSksIGxpbmV0eXBlPTIpKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeD1hZ2UsIHk9ZXN0aW1hdGUsIHltaW49Lmxvd2VyLCB5bWF4PS51cHBlciwgZ3JvdXA9c2V4LCBjb2xvdXI9c2V4LCBzaGFwZT1zZXgpLAogICAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC41KSkgKwogIHNjYWxlX2NvbG91cl9tYW51YWwodmFsdWVzID0gYygiI0NEN0FDNSIsICJjYWRldGJsdWUzIiksIG5hbWU9IiIpICsKICBzY2FsZV9zaGFwZShuYW1lPSIiKSArCiAgbGFicyh4PSIiLAogICAgICAgeT0iUmVsYXRpdmUgcmF0ZSAoOTUlIFVJKSIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsCiAgICAgICAgcGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSkKCiNzbG9wZSBwbG90CnNsb3BlX2dfYWdlX3NleCA8LSBzbG9wZV9zdW1tYXJ5X2FnZV9zZXggJT4lCiAgbXV0YXRlKHNleCA9IGNhc2Vfd2hlbihzZXg9PSJNIiB+ICJNYWxlIiwKICAgICAgICAgICAgICAgICAgICAgICAgIHNleD09IkYiIH4gIkZlbWFsZSIpKSAlPiUKICBtdXRhdGUoYWdlID0gY2FzZV93aGVuKGFnZT09IjAwXzA1IiB+ICIwIHRvIDV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjA2XzE1IiB+ICIwNiB0byAxNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMTZfMjUiIH4gIjE2IHRvIDI1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIyNl8zNSIgfiAiMjYgdG8gMzV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjM2XzQ1IiB+ICIzNiB0byA0NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNDZfNTUiIH4gIjQ2IHRvIDU1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI1Nl82NSIgfiAiNTYgdG8gNjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjY1KyIgfiAiNjUgJiB1cCB5IikpICU+JQogIGdncGxvdCgpICsKICBnZW9tX2hsaW5lKGFlcyh5aW50ZXJjZXB0PTEpLCBsaW5ldHlwZT0yKSsKICBnZW9tX3BvaW50cmFuZ2UoYWVzKHg9YWdlLCB5PWVzdGltYXRlLCB5bWluPS5sb3dlciwgeW1heD0udXBwZXIsIGdyb3VwPXNleCwgY29sb3VyPXNleCwgc2hhcGU9c2V4KSwKICAgICAgICAgICAgICAgICAgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNSkpICsKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNDRDdBQzUiLCAiY2FkZXRibHVlMyIpLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGUobmFtZT0iIikgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9IlJlbGF0aXZlIHJhdGUgKDk1JSBVSSkiKSArCiAgdGhlbWVfZ2dkaXN0KCkgKwogIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iLAogICAgICAgIHBhbmVsLmJvcmRlciA9IGVsZW1lbnRfcmVjdChjb2xvdXIgPSAiZ3JleTc4IiwgZmlsbD1OQSkpCgoKYGBgCgoKIyMjIyA5LjMgQ29tcGFyZWQgdG8gY291bnRlcmZhY3R1YWwKCmBgYHtyfQoKY291bnRlcmZhY3RfYWdlX3NleCA8LQogICAgICBhZGRfZXByZWRfZHJhd3Mob2JqZWN0ID0gbV9hZ2Vfc2V4LAogICAgICAgICAgICAgICAgICAgICAgbmV3ZGF0YSA9IG1kYXRhX2FnZV9zZXggJT4lCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCh5ZWFyLCB5ZWFyMiwgeV9udW0sIGFnZSwgc2V4KSAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXV0YXRlKGFjZl9wZXJpb2QgPSAiYS4gcHJlLWFjZiIpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdCh5ZWFyLCBhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZF9jb3VudGVyZiA9IC5lcHJlZCkKICAKI0NhbGN1YXRlIHByZWRpY3RlZCBudW1iZXIgb2YgY2FzZXMgcGVyIGRyYXcsIHRoZW4gc3VtbWFyaXNlLgpwb3N0X2NoYW5nZV9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHVuZ3JvdXAoKSAlPiUKICAgICAgc2VsZWN0KHllYXIsIGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAKICAKI2ZvciB0aGUgb3ZlcmFsbCBwZXJpb2QKY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgpICU+JQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdXRhdGUoYWNmX3BlcmlvZCA9ICJhLiBwcmUtYWNmIikpICU+JQogICAgICBmaWx0ZXIoeWVhcj4xOTU3KSAlPiUKICAgICAgc2VsZWN0KGFnZSwgc2V4LCAuZHJhdywgLmVwcmVkKSAgJT4lCiAgICAgIGdyb3VwX2J5KGFnZSwgc2V4LCAuZHJhdykgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWRfY291bnRlcmYgPSBzdW0oLmVwcmVkKSkgJT4lCiAgICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKQogIAojQ2FsY3VhdGUgaW5jaWRlbmNlIHBlciBkcmF3LCB0aGVuIHN1bW1hcmlzZS4KcG9zdF9jaGFuZ2Vfb3ZlcmFsbF9hZ2Vfc2V4IDwtCiAgICAgIGFkZF9lcHJlZF9kcmF3cyhvYmplY3QgPSBtX2FnZV9zZXgsCiAgICAgICAgICAgICAgICAgICAgICBuZXdkYXRhID0gbWRhdGFfYWdlX3NleCAlPiUKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0KHllYXIsIHllYXIyLCB5X251bSwgYWdlLCBzZXgsIGFjZl9wZXJpb2QpKSAlPiUKICAgICAgZmlsdGVyKHllYXI+MTk1NykgJT4lCiAgICAgIHNlbGVjdChhZ2UsIHNleCwgLmRyYXcsIC5lcHJlZCkgJT4lCiAgICAgIGdyb3VwX2J5KC5kcmF3LCBhZ2UsIHNleCkgJT4lCiAgICAgIHN1bW1hcmlzZSguZXByZWQgPSBzdW0oLmVwcmVkKSkgCiAgCmNvdW50ZXJfcG9zdF9vdmVyYWxsX2FnZV9zZXggPC0KICBsZWZ0X2pvaW4oY291bnRlcmZhY3Rfb3ZlcmFsbF9hZ2Vfc2V4LCBwb3N0X2NoYW5nZV9vdmVyYWxsX2FnZV9zZXgpICU+JQogICAgbXV0YXRlKGNhc2VzX2F2ZXJ0ZWQgPSAuZXByZWRfY291bnRlcmYtLmVwcmVkLAogICAgICAgICAgIHBjdF9jaGFuZ2UgPSAoLmVwcmVkIC0gLmVwcmVkX2NvdW50ZXJmKS8uZXByZWRfY291bnRlcmYpICU+JQogICAgZ3JvdXBfYnkoYWdlLCBzZXgpICU+JQogICAgbWVhbl9xaShjYXNlc19hdmVydGVkLCBwY3RfY2hhbmdlKSAlPiUKICAgIHVuZ3JvdXAoKSAlPiUKICAgIG11dGF0ZSh5ZWFyID0gIk92ZXJhbGwgKDE5NTgtMTk2MykiKSAKCgphZ2Vfc2V4X3R4dCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JQogIG11dGF0ZShhY3Jvc3MoYyhjYXNlc19hdmVydGVkOmNhc2VzX2F2ZXJ0ZWQudXBwZXIpLCBudW1iZXJfZm9ybWF0KGFjY3VyYWN5ID0gMC4xLCBiaWcubWFyayA9ICIsIikpKSAlPiUKICBtdXRhdGUoYWNyb3NzKGMocGN0X2NoYW5nZTpwY3RfY2hhbmdlLnVwcGVyKSwgcGVyY2VudCwgYWNjdXJhY3k9MC4xKSkgJT4lCiAgdHJhbnNtdXRlKHllYXIgPSBhcy5jaGFyYWN0ZXIoeWVhciksCiAgICAgICAgICAgIHNleCA9IHNleCwKICAgICAgICAgICAgYWdlID0gYWdlLAogICAgICAgICAgICBjYXNlc19hdmVydGVkID0gZ2x1ZTo6Z2x1ZSgie2Nhc2VzX2F2ZXJ0ZWR9XG4oe2Nhc2VzX2F2ZXJ0ZWQubG93ZXJ9IHRvIHtjYXNlc19hdmVydGVkLnVwcGVyfSkiKSwKICAgICAgICAgICAgcGN0X2NoYW5nZSA9IGdsdWU6OmdsdWUoIntwY3RfY2hhbmdlfVxuKHtwY3RfY2hhbmdlLmxvd2VyfSB0byB7cGN0X2NoYW5nZS51cHBlcn0pIikpCgoKYWdlX3NleF90eHQgJT4lIGRhdGF0YWJsZSgpCgoKYGBgCgpgYGB7cn0KCmNvdW50ZXJmYWN0dWFsX2dfYWdlX3NleCA8LSBjb3VudGVyX3Bvc3Rfb3ZlcmFsbF9hZ2Vfc2V4ICU+JSAKICBtdXRhdGUoc2V4ID0gY2FzZV93aGVuKHNleD09Ik0iIH4gIk1hbGUiLAogICAgICAgICAgICAgICAgICAgICAgICAgc2V4PT0iRiIgfiAiRmVtYWxlIikpICU+JQogIG11dGF0ZShhZ2UgPSBjYXNlX3doZW4oYWdlPT0iMDBfMDUiIH4gIjAgdG8gNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMDZfMTUiIH4gIjA2IHRvIDE1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSIxNl8yNSIgfiAiMTYgdG8gMjV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjI2XzM1IiB+ICIyNiB0byAzNXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iMzZfNDUiIH4gIjM2IHRvIDQ1eSIsCiAgICAgICAgICAgICAgICAgICAgICAgICBhZ2U9PSI0Nl81NSIgfiAiNDYgdG8gNTV5IiwKICAgICAgICAgICAgICAgICAgICAgICAgIGFnZT09IjU2XzY1IiB+ICI1NiB0byA2NXkiLAogICAgICAgICAgICAgICAgICAgICAgICAgYWdlPT0iNjUrIiB+ICI2NSAmIHVwIHkiKSkgJT4lCiAgZ2dwbG90KCkgKwogIGdlb21fcG9pbnRyYW5nZShhZXMoeCA9IGFnZSwgeT1jYXNlc19hdmVydGVkLCB5bWluPWNhc2VzX2F2ZXJ0ZWQubG93ZXIsIHltYXg9Y2FzZXNfYXZlcnRlZC51cHBlciwgY29sb3VyPXNleCwgc2hhcGU9c2V4KSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGg9MC41KSkgKyAKICBzY2FsZV9jb2xvdXJfbWFudWFsKHZhbHVlcyA9IGMoIiNDRDdBQzUiLCAiY2FkZXRibHVlMyIpLCBuYW1lPSIiKSArCiAgc2NhbGVfc2hhcGUobmFtZT0iIikgKwogIHNjYWxlX3lfY29udGludW91cyhsYWJlbHMgPSBjb21tYSkgKwogIGxhYnMoeD0iIiwKICAgICAgIHk9Ik51bWJlciAoOTUlIFVJKSIsCiAgICAgICBjb2xvdXI9IiIpICsKICB0aGVtZV9nZ2Rpc3QoKSArCiAgdGhlbWUocGFuZWwuYm9yZGVyID0gZWxlbWVudF9yZWN0KGNvbG91ciA9ICJncmV5NzgiLCBmaWxsPU5BKSwKICAgICAgICBsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIikKCmNvdW50ZXJmYWN0dWFsX2dfYWdlX3NleApgYGAKCkpvaW4gdG9nZXRoZXIgZm9yIEZpZ3VyZSAzLgoKCmBgYHtyfQoKKHBlYWtfZ19hZ2Vfc2V4ICsgbGV2ZWxfZ19hZ2Vfc2V4KSAvIChzbG9wZV9nX2FnZV9zZXggKyBjb3VudGVyZmFjdHVhbF9nX2FnZV9zZXgpICsgcGxvdF9hbm5vdGF0aW9uKHRhZ19sZXZlbHMgPSAiQSIpICsgcGxvdF9sYXlvdXQoZ3VpZGVzID0gImNvbGxlY3QiKSAmIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJib3R0b20iKQoKZ2dzYXZlKGhlcmUoImZpZ3VyZXMvZjMucG5nIiksIHdpZHRoID0gMTIsIGhlaWdodD04KQoKCmBgYAoKCgojIyMgMTAgRGl2aXNpb24gbW9kZWwKCldhcyB1cHRha2Ugb2YgQ1hSIGF0IGRpdmlzaW9uIGxldmVsIGFzc29jaWF0ZWQgd2l0aCBncmVhdGVkIGltcGFjdD8KCiMgYGBge3J9CiMgCiMgbV9kaXZpc2lvbiA8LSBicm0oCiMgICBjYXNlcyB+IDEgKyB5X251bSphY2ZfcGVyaW9kICsgKDEgKyB5X251bSphY2ZfcGVyaW9kIHwgd2FyZCkgKyBvZmZzZXQobG9nKHBvcHVsYXRpb25fd2l0aG91dF9pbnN0X3NoaXApKSwKIyAgICAgICAgICAgICAgICAgICBkYXRhID0gbWRhdGEsCiMgICAgICAgICAgICAgICAgICAgZmFtaWx5ID0gbmVnYmlub21pYWwoKSwKIyAgICAgICAgICAgICAgICAgICBzZWVkID0gMTIzNCwKIyAgICAgICAgICAgICAgICAgICBjaGFpbnMgPSA0LCBjb3JlcyA9IDQsCiMgICAgICAgICAgICAgICAgICAgcHJpb3IgPSBwcmlvcihub3JtYWwoMCwxKSwgY2xhc3MgPSBJbnRlcmNlcHQpICsKIyAgICAgICAgICAgICAgICAgICAgICAgICAgIHByaW9yKGdhbW1hKDAuMDEsIDAuMDEpLCBjbGFzcyA9IHNoYXBlKSArCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihub3JtYWwoMCwgMSksIGNsYXNzID0gYikgKwojICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJpb3IoZXhwb25lbnRpYWwoMSksIGNsYXNzPXNkKSArCiMgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmlvcihsa2ooNCksIGNsYXNzPWNvciksCiMgICBjb250cm9sID0gbGlzdChhZGFwdF9kZWx0YSA9IDAuOSkpCiMgCiMgYGBgCgo=